package com.cloudkinto.service.order.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cloudkinto.bo.order.OrderVdfQueryBo;
import com.cloudkinto.common.DicBusinessItemConstant;
import com.cloudkinto.common.common.Base64AndFileStreamUtil;
import com.cloudkinto.common.constant.GlobalConstants;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.StringsUtil;
import com.cloudkinto.common.utils.TimeUtils;
import com.cloudkinto.common.utils.XmlUtils;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.OrderAmazonVdfDao;
import com.cloudkinto.dao.StockRecordDao;
import com.cloudkinto.dao.StorageDao;
import com.cloudkinto.entity.*;
import com.cloudkinto.service.amazon.AmazonBaseServiceImpl;
import com.cloudkinto.service.company.CompanyService;
import com.cloudkinto.service.file.FileService;
import com.cloudkinto.service.operate.OperateRecordService;
import com.cloudkinto.service.order.OrderAmazonVdfItemService;
import com.cloudkinto.service.order.OrderAmazonVdfService;
import com.cloudkinto.service.order.delayTask.DelayTaskService;
import com.cloudkinto.service.order.delayTask.GetShippingLabelDelay;
import com.cloudkinto.service.order.vo.amazon.vdfOrder.*;
import com.cloudkinto.service.orderoutput.OrderOutputService;
import com.cloudkinto.service.orderoutput.openapivo.OpenApiDFOrderReq;
import com.cloudkinto.service.orderoutput.openapivo.OpenApiOrderOutputAddReq;
import com.cloudkinto.service.orderoutput.openapivo.OpenApiOrderOutputProductAddReq;
import com.cloudkinto.service.orderoutput.vo.OrderOutputAddReq;
import com.cloudkinto.service.orderoutput.vo.OrderOutputPackageAddReq;
import com.cloudkinto.service.orderoutput.vo.OrderOutputProductAddReq;
import com.cloudkinto.service.product.ProductInfoService;
import com.cloudkinto.service.region.JpRegionService;
import com.cloudkinto.service.shipprice.ShipPriceService;
import com.cloudkinto.service.shop.ShopService;
import com.cloudkinto.utils.BeanCopierUtils;
import com.cloudkinto.utils.ZplConverterUtils;
import com.cloudkinto.utils.amazon.AmazonUtil;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.List;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <p>
 * 亚马逊供应商api订单 供应商直接供货
 * </p>
 *
 * @author ding
 * @since 2024-06-19
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class OrderAmazonVdfServiceImpl extends AmazonBaseServiceImpl<OrderAmazonVdfDao, OrderAmazonVdfDo> implements OrderAmazonVdfService {
    @Autowired
    private OrderAmazonVdfDao dao;
    @Autowired
    private OrderAmazonVdfItemService orderAmazonVdfItemService;
    @Autowired
    private OperateRecordService operateRecordDao;
    @Autowired
    private ProductInfoService productInfoService;
    @Autowired
    private JpRegionService mRegionService;
    @Autowired
    private ShipPriceService shipPriceService;
    @Autowired
    private StorageDao storageDao;
    @Autowired
    private StockRecordDao stockDao;
    @Lazy
    @Autowired
    private OrderOutputService orderOutputService;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;
    @Autowired
    private ShopService shopService;
    @Autowired
    private CompanyService companyService;
    @Lazy
    @Autowired
    private DelayTaskService delayTaskService;

    @Value("${gbc.uploadPath.filePathTemp}")
    private String filePathTemp;

    @Autowired
    private FileService fileService;

    private String STSSESSIONTOKEN = "STSSESSIONSTOKEN";
    private String AMZACCESSTOKEN = "AMZACCESSTOKEN:";
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private TransactionTemplate transactionTemplate;


    private Map<String, String> shipMethodStorage = new HashMap<>(16);

    @Override
    public Object add(Object req, Long userId) {
        OrderAmazonVdfDo entityDo = new OrderAmazonVdfDo();
        BeanUtils.copyProperties(req, entityDo);
        handlerAddBefore(entityDo, userId);
        baseMapper.insert(entityDo);
        return handlerAddAfter(entityDo);
    }

    /**
     * 做新增之前要执行的业务定制处理
     */
    private void handlerAddBefore(OrderAmazonVdfDo entityDo, Long userId) {
        entityDo.setCreateBy(userId);
        entityDo.setCreateTime(new Date());
        entityDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
    }

    /**
     * 将新增的do转换成要返回的实体
     */
    private Object handlerAddAfter(OrderAmazonVdfDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public Object update(Object req, Long userId) {
        /*OrderAmazonVdfDo entityDo = dao.selectById(req.getId());
        BeanUtils.copyProperties(req, entityDo);
        handlerUpdateBefore(entityDo, userId);
        dao.updateById(entityDo);
        return handlerUpdateAfter(entityDo);*/
        return null;
    }


    /**
     * 做修改之前要执行的业务定制处理
     */
    private void handlerUpdateBefore(OrderAmazonVdfDo entityDo, Long userId) {
        entityDo.setUpdateBy(userId);
        entityDo.setUpdateTime(new Date());
    }

    /**
     * 做修改之后要执行的业务定制处理
     */
    private Object handlerUpdateAfter(OrderAmazonVdfDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public int delete(Long id, Long userId) {
        return baseMapper.deleteById(id);
    }


    @Override
    public Object detail(Long id) {
        OrderAmazonVdfDo entityDo = baseMapper.selectById(id);
        VdfOrderDetailVo res = new VdfOrderDetailVo();
        BeanUtils.copyProperties(entityDo, res);
        return handlerDetailAfter(res);
    }

    /**
     * 补充详情
     */
    private Object handlerDetailAfter(VdfOrderDetailVo res) {
        //查询订单商品
        List<OrderAmazonVdfItemDo> itemList = orderAmazonVdfItemService.list(Wrappers.<OrderAmazonVdfItemDo>lambdaQuery().eq(OrderAmazonVdfItemDo::getPurchaseOrderNumber, res.getPurchaseOrderNumber()));
        //转换实体
        List<VdfOrderItemVo> itemVoList = BeanCopierUtils.listCopyMapper(itemList, OrderAmazonVdfItemDo.class, VdfOrderItemVo.class);
        res.setItemList(itemVoList);
        //查询日志
        //todo long
        return res;
    }

    @Override
    public PageResult getListPage(OrderVdfQueryBo bo) {
        LambdaQueryWrapper<OrderAmazonVdfDo> wrapper = queryBuild(bo);
        IPage<OrderAmazonVdfDo> page = new Page<>(bo.getCurrent(), bo.getPageSize());
        page = this.page(page, wrapper);
        List<VdfOrderVo> orderList = BeanCopierUtils.listCopyMapper(page.getRecords(), OrderAmazonVdfDo.class, VdfOrderVo.class);
        handlerPageList(orderList);
        return new PageResult(orderList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
    }

    /**
     * 分页数据前置处理
     */
    private void handlerPageList(List<VdfOrderVo> orderList) {
        orderList.forEach(vdfOrderVo -> {
            vdfOrderVo.setShipAddress1(vdfOrderVo.getShipAddress1() + vdfOrderVo.getShipAddress2() + vdfOrderVo.getShipAddress3());
        });
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void vdfOrderSync(Long shopId, Date beforeDate, Date afterDate) {
        ShopDo shopDo = shopService.getById(shopId);
        String nextToken = "";
        List<VdfOrderEntity> orderList = new ArrayList<>();
        do {
            Map<String, Object> parametersMap = new HashMap<>(16);

            if (StringUtils.isNotBlank(nextToken)) {
                parametersMap.put("nextToken", nextToken);
            }
            parametersMap.put("createdAfter", new SimpleDateFormat(GlobalConstants.TIME_FORMAT_STR).format(beforeDate));
            //在查询时间上加一天
            parametersMap.put("createdBefore", new SimpleDateFormat(GlobalConstants.TIME_FORMAT_STR).format(new Date(afterDate.getTime() + 24 * 60 * 60 * 1000 - 1)));
            //发货仓库的供应商仓库标识符。如果未指定，则结果将包含所有仓库的订单 todo 先不做
//                parametersMap.put("shipFromPartyId", "A2QD8CZ5OYH9Q2");
            //按订单创建日期排序
            parametersMap.put("sortOrder", SortOrder.ASC.getValue());
            //如果为 true，则返回完整的采购订单详细信息。否则，仅返回采购订单号
            parametersMap.put("includeDetails", true);

            String body = null;
            try {
                body = AmazonUtil.spAPidoGet(GlobalConstants.AmazonSPAPIURL + "/vendor/directFulfillment/orders/v1/purchaseOrders", getAccessToken(shopDo), getAwsSTSSessionToken(), parametersMap);
                //到这一步说明接口调用成功了 把接口执行条件的开始时间和结束时间存放在同步表中
            } catch (Exception e) {
                e.printStackTrace();
                log.error("同步vdf Order失败，原因：", e);
            }
            if (StringUtils.isBlank(body)) {
                continue;
            }
            JSONObject bodyJb = JSONObject.parseObject(body);
            //循环调接口 如果返回结果为空 跳过继续下一条
            if (bodyJb.isEmpty()) {
                continue;
            }
            if (bodyJb.get("errors") != null) {
                JSONArray errors = bodyJb.getJSONArray("errors");
                if (errors.size() > 0) {
                    log.error("店铺：" + shopDo.getShopName() + "同步vdf订单失败，原因：" + errors);
                } else {
                    log.error("店铺：" + shopDo.getShopName() + "同步vdf订单失败，原因：未知");
                }
            } else {
                List<VdfOrderEntity> vdfOrderEntityList = JSONArray.parseArray(bodyJb.getJSONObject("payload").getString("orders"), VdfOrderEntity.class);
                if (CollUtil.isNotEmpty(vdfOrderEntityList)) {
                    orderList.addAll(vdfOrderEntityList);
                }
            }
            if (bodyJb.getJSONObject("payload") != null && bodyJb.getJSONObject("payload").getJSONObject("pagination") != null) {
                nextToken = bodyJb.getJSONObject("payload").getJSONObject("pagination").getString("nextToken");
            } else {
                nextToken = null;
            }
            try {
                //间隔120毫秒,平台限制每秒最多调用10次
                TimeUnit.MILLISECONDS.sleep(120);
            } catch (InterruptedException ignored) {

            }
        } while (StringUtils.isNotBlank(nextToken));
        //分批多线程插入数据
        this.insertVdf(orderList, shopDo.getId(), shopDo.getCompanyId());
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void insertVdf(List<VdfOrderEntity> vdfOrderEntityList, Long shopId, Long companyId) {
        if (CollUtil.isEmpty(vdfOrderEntityList)) {
            return;
        }
        //为获取发货标签准备数据
        HashMap<String, Long> purchaseAndShopIdMap = new HashMap<>(vdfOrderEntityList.size() / 3 * 4 + 1);
        List<List<VdfOrderEntity>> batchList = ListUtil.partition(vdfOrderEntityList, 500);
        List<CompletableFuture<Void>> futures = new ArrayList<>();

        for (List<VdfOrderEntity> batch : batchList) {
            // 异步处理每批数据
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                List<OrderAmazonVdfDo> doList = new ArrayList<>(batch.size());
                List<OrderAmazonVdfItemDo> itemDoList = new ArrayList<>(batch.size() / 2 * 3);
                //po号获取
                Set<String> poNoSet = batch.stream().map(VdfOrderEntity::getPurchaseOrderNumber).collect(Collectors.toSet());
                //po号匹配订单主表记录
                Map<String, OrderAmazonVdfDo> poNoMatchOrderDo = baseMapper.selectList(
                        Wrappers.<OrderAmazonVdfDo>lambdaQuery()
                                .select(
                                        OrderAmazonVdfDo::getId,
                                        OrderAmazonVdfDo::getPurchaseOrderNumber,
                                        OrderAmazonVdfDo::getLabelFileUrl,
                                        OrderAmazonVdfDo::getOrderStatus,
                                        OrderAmazonVdfDo::getIsPslipRequired,
                                        OrderAmazonVdfDo::getPackingSlipUrl
                                )
                                .in(OrderAmazonVdfDo::getPurchaseOrderNumber, poNoSet)
                ).stream().collect(Collectors.toMap(OrderAmazonVdfDo::getPurchaseOrderNumber, val -> val, (val1, val2) -> val1));
                //po号匹配订单子表记录
                Map<String, List<OrderAmazonVdfItemDo>> poNoMatchOrderItem = orderAmazonVdfItemService.list(
                        Wrappers.<OrderAmazonVdfItemDo>lambdaQuery()
                                .select(OrderAmazonVdfItemDo::getPurchaseOrderNumber)
                                .in(OrderAmazonVdfItemDo::getPurchaseOrderNumber, poNoSet)
                ).stream().collect(Collectors.groupingBy(OrderAmazonVdfItemDo::getPurchaseOrderNumber));
                transactionTemplate.execute(status -> {
                    try {
                        for (VdfOrderEntity vdfOrderEntity : batch) {
                            //采购订单号
                            String purchaseOrderNumber = vdfOrderEntity.getPurchaseOrderNumber();
                            String partyId = vdfOrderEntity.getOrderDetails().getShipFromParty().getPartyId();
                            if (companyId.intValue() == 84 && !"FTHA".equals(partyId) && !"FTHB".equals(partyId) && !"GOER".equals(partyId) && !"GOES".equals(partyId)) {
                                continue;
                            }
                            //判断此订单是否存在
                            OrderAmazonVdfDo one = poNoMatchOrderDo.get(purchaseOrderNumber);
                            //采购订单详情
                            VdfOrderDetailsEntity orderDetails = vdfOrderEntity.getOrderDetails();
                            //已存在不操作主表
                            if (Objects.nonNull(one)) {
                                if (!one.getOrderStatus().equals(orderDetails.getOrderStatus().getValue())) {
                                    this.lambdaUpdate()
                                            .set(OrderAmazonVdfDo::getOrderStatus, orderDetails.getOrderStatus().getValue())
                                            .eq(OrderAmazonVdfDo::getPurchaseOrderNumber, purchaseOrderNumber)
                                            .update();
                                }
                                if ((one.getIsPslipRequired() && StringUtils.isEmpty(one.getPackingSlipUrl()))
                                        || StringUtils.isEmpty(one.getLabelFileUrl())) {
                                    //为获取发货标签准备数据
                                    purchaseAndShopIdMap.put(purchaseOrderNumber, shopId);
                                }
                            } else {
                                //为获取发货标签准备数据
                                purchaseAndShopIdMap.put(purchaseOrderNumber, shopId);
                                OrderAmazonVdfDo orderAmazonVdfDo = new OrderAmazonVdfDo();
                                BeanUtils.copyProperties(orderDetails, orderAmazonVdfDo);
                                orderAmazonVdfDo.setPurchaseOrderNumber(purchaseOrderNumber);
                                //订单日期加9小时
                                orderAmazonVdfDo.setOrderDate(
                                        DateUtil.parse(
                                                orderDetails.getOrderDate(),
                                                GlobalConstants.TIME_FORMAT_STR
                                        ).offset(DateField.HOUR, 9)
                                );
                                orderAmazonVdfDo.setOrderStatus(orderDetails.getOrderStatus().getValue());
                                //装运详情 开始
                                ShipmentDetails shipmentDetails = orderDetails.getShipmentDetails();
                                orderAmazonVdfDo.setIsPriorityShipment(shipmentDetails.isPriorityShipment());
                                orderAmazonVdfDo.setIsScheduledDeliveryShipment(shipmentDetails.isScheduledDeliveryShipment());
                                orderAmazonVdfDo.setIsPslipRequired(shipmentDetails.isPslipRequired());
                                orderAmazonVdfDo.setIsGift(shipmentDetails.isGift());
                                orderAmazonVdfDo.setShipMethod(shipmentDetails.getShipMethod());
                                orderAmazonVdfDo.setRequiredShipDate(
                                        DateUtil.parse(
                                                shipmentDetails.getShipmentDates().getRequiredShipDate(),
                                                GlobalConstants.TIME_FORMAT_STR
                                        )
                                );
                                orderAmazonVdfDo.setPromisedDeliveryDate(
                                        DateUtil.parse(
                                                shipmentDetails.getShipmentDates().getPromisedDeliveryDate(),
                                                GlobalConstants.TIME_FORMAT_STR
                                        )
                                );
                                orderAmazonVdfDo.setMessageToCustomer(shipmentDetails.getMessageToCustomer());
                                //装运详情 结束
                                orderAmazonVdfDo.setTaxTotalJson(JSONArray.toJSONString(orderDetails.getTaxTotal().getTaxLineItem()));
                                orderAmazonVdfDo.setTaxTotal(
                                        BigDecimal.valueOf(
                                                orderDetails.getTaxTotal()
                                                        .getTaxLineItem().stream()
                                                        .mapToDouble(i -> i.getTaxAmount().getAmount().doubleValue())
                                                        .sum()
                                        )
                                );
                                orderAmazonVdfDo.setSellingParty(JSONUtil.toJsonStr(orderDetails.getSellingParty()));
                                PartyIdentification shipFromParty = orderDetails.getShipFromParty();
                                orderAmazonVdfDo.setShipFromParty(JSONUtil.toJsonStr(shipFromParty));
                                orderAmazonVdfDo.setShipFromPartyId(shipFromParty.getPartyId());
                                orderAmazonVdfDo.setBillToParty(JSONUtil.toJsonStr(orderDetails.getBillToParty()));
                                //收货方的名称/地址和税务详细信息 begin
                                Address shipToParty = orderDetails.getShipToParty();
                                orderAmazonVdfDo.setShipName(shipToParty.getName());
                                orderAmazonVdfDo.setShipAttention(shipToParty.getAttention());
                                orderAmazonVdfDo.setShipAddress1(shipToParty.getAddressLine1());
                                orderAmazonVdfDo.setShipAddress2(shipToParty.getAddressLine2());
                                orderAmazonVdfDo.setShipAddress3(shipToParty.getAddressLine3());
                                orderAmazonVdfDo.setShipCity(shipToParty.getCity());
                                orderAmazonVdfDo.setShipCounty(shipToParty.getCounty());
                                orderAmazonVdfDo.setShipDistrict(shipToParty.getDistrict());
                                orderAmazonVdfDo.setShipStateOrRegion(shipToParty.getStateOrRegion());
                                orderAmazonVdfDo.setShipPostalCode(shipToParty.getPostalCode());
                                orderAmazonVdfDo.setShipCountryCode(shipToParty.getCountryCode());
                                orderAmazonVdfDo.setShipPhone(shipToParty.getPhone());
                                //收货方的名称/地址和税务详细信息 end
                                orderAmazonVdfDo.setCompanyId(companyId);
                                orderAmazonVdfDo.setShopId(shopId);
                                doList.add(orderAmazonVdfDo);
                            }
                            //此采购订单中的物料列表
                            List<OrderItem> orderItemList = orderDetails.getItems();
                            //判断此订单是否存在
                            List<OrderAmazonVdfItemDo> itemOnes = poNoMatchOrderItem.get(purchaseOrderNumber);
                            if (CollUtil.isNotEmpty(itemOnes)) {
                                if (itemOnes.size() != orderItemList.size()) {
                                    orderAmazonVdfItemService.removeByIds(itemOnes.stream().map(OrderAmazonVdfItemDo::getId).collect(Collectors.toList()));
                                } else {
                                    continue;
                                }
                            }
                            orderItemList.forEach(item -> {
                                OrderAmazonVdfItemDo vdfItemDo = new OrderAmazonVdfItemDo();
                                vdfItemDo.setPurchaseOrderNumber(purchaseOrderNumber);
                                vdfItemDo.setItemSequenceNumber(Integer.valueOf(item.getItemSequenceNumber()));
                                vdfItemDo.setBuyerProductIdentifier(item.getBuyerProductIdentifier());
                                vdfItemDo.setVendorProductIdentifier(item.getVendorProductIdentifier());
                                vdfItemDo.setTitle(item.getTitle());
                                vdfItemDo.setOrderedQuantity(item.getOrderedQuantity().getAmount());
                                if (ObjectUtil.isNotNull(item.getScheduledDeliveryShipment())) {
                                    vdfItemDo.setScheduledDeliveryServiceType(item.getScheduledDeliveryShipment().getScheduledDeliveryServiceType());
                                    vdfItemDo.setEarliestNominatedDeliveryDate(
                                            DateUtil.parse(
                                                    item.getScheduledDeliveryShipment().getEarliestNominatedDeliveryDate(),
                                                    GlobalConstants.TIME_FORMAT_STR
                                            )
                                    );
                                    vdfItemDo.setLatestNominatedEliveryDate(
                                            DateUtil.parse(
                                                    item.getScheduledDeliveryShipment().getLatestNominatedDeliveryDate(),
                                                    GlobalConstants.TIME_FORMAT_STR
                                            )
                                    );
                                }
                                if (ObjectUtil.isNotNull(item.getGiftDetails())) {
                                    vdfItemDo.setGiftMessage(item.getGiftDetails().getGiftMessage());
                                    vdfItemDo.setGiftWrapId(item.getGiftDetails().getGiftWrapId());
                                }
                                vdfItemDo.setNetPriceJson(JSONUtil.toJsonStr(item.getNetPrice()));
                                vdfItemDo.setNetPrice(item.getNetPrice().getAmount());
                                vdfItemDo.setTaxDetailsJson(JSONArray.toJSONString(item.getTaxDetails().getTaxLineItem()));
                                //税总额
                                vdfItemDo.setTaxDetails(
                                        BigDecimal.valueOf(
                                                item.getTaxDetails()
                                                        .getTaxLineItem().stream()
                                                        .mapToDouble(i -> i.getTaxAmount().getAmount().doubleValue())
                                                        .sum()
                                        )
                                );
                                if (ObjectUtil.isNotNull(item.getTotalPrice())) {
                                    vdfItemDo.setTotalPriceJson(JSONUtil.toJsonStr(item.getTotalPrice()));
                                    vdfItemDo.setTotalPrice(item.getTotalPrice().getAmount());
                                }
                                itemDoList.add(vdfItemDo);
                            });
                        }
                        if (CollUtil.isNotEmpty(doList)) {
                            //写入主表数据
                            baseMapper.insertBatch(doList);
                        }
                        //写入子表数据
                        if (CollUtil.isNotEmpty(itemDoList)) {
                            orderAmazonVdfItemService.insertBatch(itemDoList);
                        }
                        return null;
                    } catch (Exception e) {
                        status.setRollbackOnly();
                        log.error("vdf订单插入有一批操作失败：", e);
                    }
                    return null;
                });
            }, threadPoolExecutor);
            futures.add(future);
        }
        // 等待分批插入订单信息完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
//        shipMethodStorage.clear();
        //获取发货标签
        CompletableFuture.runAsync(() -> {
            try {
                this.getVdfShippingLabel(purchaseAndShopIdMap, true, false);
            } catch (RuntimeException e) {
                log.error("同步vdf订单后，获取发货标签失败", e);
            }
        }, threadPoolExecutor);
        //获取装箱单
        CompletableFuture.runAsync(() -> {
            try {
                this.getVdfPackingSlipList(purchaseAndShopIdMap);
            } catch (RuntimeException e) {
                log.error("同步vdf订单后，获取装箱单失败", e);
            }
        }, threadPoolExecutor);

    }

    /**
     * 获取订单的发货标签信息，包括采购订单编号、销售方、发货方、标签格式和包裹详细信息。
     */
    @Override
    @Retryable(value = RuntimeException.class, maxAttempts = 2, backoff = @Backoff(delay = 20000, multiplier = 2))
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void getVdfShippingLabel(Map<String, Long> purchaseAndShopIdMap, boolean isCreateLabel, boolean isOverwrite) throws RuntimeException {
        if (CollUtil.isEmpty(purchaseAndShopIdMap)) {
            return;
        }
        Map<String, OrderAmazonVdfDo> poNoMatchOrderDo = baseMapper.selectList(
                Wrappers.<OrderAmazonVdfDo>lambdaQuery()
                        .select(
                                OrderAmazonVdfDo::getPurchaseOrderNumber,
                                OrderAmazonVdfDo::getLabelFileUrl,
                                OrderAmazonVdfDo::getId
                        )
                        .in(OrderAmazonVdfDo::getPurchaseOrderNumber, purchaseAndShopIdMap.keySet())
        ).stream().collect(Collectors.toMap(OrderAmazonVdfDo::getPurchaseOrderNumber, val -> val, (val1, val2) -> val1));
        Map<Long, ShopDo> shopDoMap = new HashMap<>();
        boolean isRetry = false;
        HashMap<String, String> sendOutData = new HashMap<>(purchaseAndShopIdMap.size());
        List<String> po = new ArrayList<>();
        for (Map.Entry<String, Long> entry : purchaseAndShopIdMap.entrySet()) {
            ShopDo shopDo = shopDoMap.get(entry.getValue());
            if (Objects.isNull(shopDo)) {
                shopDo = shopService.getById(entry.getValue());
                shopDoMap.put(entry.getValue(), shopDo);
            }
            //存在发货标签直接跳过
            OrderAmazonVdfDo one = poNoMatchOrderDo.get(entry.getKey());
            if (Objects.isNull(one) || (!isOverwrite && StringUtils.isNotBlank(one.getLabelFileUrl()))) {
                continue;
            }
            String body = null;
            try {
                try {
                    TimeUnit.MILLISECONDS.sleep(130);
                } catch (InterruptedException ignored) {

                }
                body = AmazonUtil.spAPidoGet(
                        GlobalConstants.AmazonSPAPIURL + "/vendor/directFulfillment/shipping/v1/shippingLabels/" + entry.getKey(),
                        getAccessToken(shopDo),
                        getAwsSTSSessionToken(),
                        null
                );
                //到这一步说明接口调用成功了 把接口执行条件的开始时间和结束时间存放在同步表中
            } catch (Exception e) {
                log.error("vdf获取发货标签失败，原因：", e);
            }
            if (StringUtils.isBlank(body)) {
                continue;
            }
            JSONObject bodyJb = JSONObject.parseObject(body);
            if (bodyJb.isEmpty()) {
                continue;
            }
            if (bodyJb.get("errors") != null) {
                JSONArray errors = bodyJb.getJSONArray("errors");
                if (errors.size() > 0) {
                    log.error("vdf订单号：" + entry.getKey() + "获取发货标签信息失败，原因：" + errors);
                } else {
                    log.error("vdf订单号：" + entry.getKey() + "获取发货标签信息失败，原因：" + errors);
                }
            } else if (bodyJb.getJSONObject("payload").isEmpty()) {
                log.error("vdf订单号：" + entry.getKey() + "获取发货标签信息为空");
                po.add(entry.getKey());
                isRetry = true;
            } else {
                ShippingLabel shippingLabel = JSONObject.parseObject(
                        bodyJb.getJSONObject("payload").toString(),
                        ShippingLabel.class
                );
                //扩展名
                String ext = shippingLabel.getLabelFormat().getValue();
                //面单上传服务器并获取面单基本信息
                if (CollUtil.isNotEmpty(shippingLabel.getLabelData()) && shippingLabel.getLabelData().size() > 1) {
                    //存在多个包裹有两种情况 1. 亚马逊创建 2. 自定义包裹信息创建 如果是自定义创建需要剔除其余面单
                    Optional<LabelData> needDelData = shippingLabel.getLabelData().stream()
                            .filter(
                                    labelData -> labelData.getPackageIdentifier() != null &&
                                            labelData.getPackageIdentifier().startsWith(shippingLabel.getPurchaseOrderNumber() + "-")
                            ).findAny();
                    if (needDelData.isPresent()) {
                        //剔除非自定义创建的面单
                        shippingLabel.getLabelData().removeIf(
                                labelData -> labelData.getPackageIdentifier() == null
                                        || !labelData.getPackageIdentifier().startsWith(shippingLabel.getPurchaseOrderNumber() + "-")
                        );
                    }
                }
                shippingLabel.getLabelData().forEach(labelData -> {
                    //包裹编号
                    shippingLabel.getTrackingNumber().append(labelData.getTrackingNumber()).append(",");
                    //发货方式
                    shippingLabel.setShipMethod(new StringBuilder(labelData.getShipMethod()));
                    //发货方式名称
                    shippingLabel.setShipMethodName(new StringBuilder(labelData.getShipMethodName()));
                    //缓存发货方式
                    shipMethodStorage.put(labelData.getShipMethod(), StrUtil.isEmpty(labelData.getShipMethodName()) ? labelData.getShipMethod() : labelData.getShipMethodName());
                    //面单文件名
                    String fileName = null;
                    ByteArrayInputStream bis = null;
                    if (LabelFormat.ZPL.getValue().equals(ext)) {
                        byte[] zplBytes = Base64.getDecoder().decode(labelData.getContent());
                        byte[] pdfBytes = ZplConverterUtils.convertZplToPdf(zplBytes, "5.9", "8.9");
                        if (pdfBytes != null) {
                            //成功转换成pdf
                            fileName = labelData.getTrackingNumber() + "-ShippingLabel.pdf";
                            bis = new ByteArrayInputStream(pdfBytes);
                        } else {
                            log.error("zpl file to pdf error,check whether the conversion service is available.");
                        }
                    }
                    if (bis == null) {
                        bis = new ByteArrayInputStream(Base64.getDecoder().decode(labelData.getContent()));
                    }
                    if (fileName == null) {
                        fileName = labelData.getTrackingNumber() + "-ShippingLabel." + ext;
                    }
                    //上传文件到服务器
                    Long fileId = fileService.uploadFileToFormalPath(bis, fileName);
                    //获取文件url
                    String fileUrl = fileService.getFilePath(fileId);
                    shippingLabel.getLabelFileUrl().append(fileUrl).append(",");
                });
                this.lambdaUpdate()
                        .set(OrderAmazonVdfDo::getTrackingNumber,
                                shippingLabel.getTrackingNumber()
                                        .substring(0, shippingLabel.getTrackingNumber().toString().length() - 1))
//                        .set(OrderAmazonVdfDo::getShipMethod,
//                                shippingLabel.getShipMethod()
//                                        .substring(0, shippingLabel.getShipMethod().toString().length() - 1))
//                        .set(OrderAmazonVdfDo::getShipMethodName,
//                                shippingLabel.getShipMethodName()
//                                        .substring(0, shippingLabel.getShipMethodName().toString().length() - 1))
                        .set(OrderAmazonVdfDo::getShipMethod, shippingLabel.getShipMethod().toString())
                        .set(OrderAmazonVdfDo::getShipMethodName, shippingLabel.getShipMethodName().toString())
                        .set(OrderAmazonVdfDo::getLabelFileUrl,
                                shippingLabel.getLabelFileUrl()
                                        .substring(0, shippingLabel.getLabelFileUrl().toString().length() - 1))
                        // .set(OrderAmazonVdfDo::getIsSendOut, 1)//标记已发货
                        .eq(OrderAmazonVdfDo::getPurchaseOrderNumber, shippingLabel.getPurchaseOrderNumber())
                        .update();
                // operateRecordDao.operateAddRecord(SysConstant.OPERATE_MARK_SEND, one.getId(), 1L, 10);
                if ((null == one.getIsSendOut() || 0 == one.getIsSendOut()) && (shopDo.getCompanyId().intValue() == 84 || shopDo.getCompanyId().intValue() == 591)) {
                    sendOutData.put(one.getPurchaseOrderNumber(), String.valueOf(one.getId()));
                }
            }
        }
        if (CollUtil.isNotEmpty(sendOutData)) {
            List<OrderOutputDo> exists = orderOutputService.list(
                    Wrappers.<OrderOutputDo>lambdaQuery()
                            .select(OrderOutputDo::getOrderNo)
                            .eq(OrderOutputDo::getPlatform, "vdf")
                            .in(OrderOutputDo::getOrderNo, sendOutData.keySet())
            );
            //去除已经发货的订单
            exists.forEach(orderOutputDo -> sendOutData.remove(orderOutputDo.getOrderNo()));
            CompletableFuture.runAsync(
                    () -> this.sendOut(sendOutData.values().toArray(new String[0]), 1L, 1L, true),
                    threadPoolExecutor
            );
        }
        if (CollUtil.isNotEmpty(po) && isCreateLabel) {
            this.createShippingLabelV2(po, false);
        }
        if (isRetry) {
            throw new BizException("vdf获取发货标签信息失败，重试中...");
        }
    }

    /**
     * 返回装箱单
     */
    @Retryable(value = RuntimeException.class, maxAttempts = 2, backoff = @Backoff(delay = 20000, multiplier = 2))
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void getVdfPackingSlipList(Map<String, Long> purchaseAndShopIdMap) throws RuntimeException {
        if (CollUtil.isEmpty(purchaseAndShopIdMap)) {
            return;
        }
        Map<String, OrderAmazonVdfDo> poNoMatchOrderDo = baseMapper.selectList(
                Wrappers.<OrderAmazonVdfDo>lambdaQuery()
                        .select(OrderAmazonVdfDo::getPackingSlipUrl, OrderAmazonVdfDo::getIsPslipRequired)
                        .in(OrderAmazonVdfDo::getPurchaseOrderNumber, purchaseAndShopIdMap.keySet())
        ).stream().collect(Collectors.toMap(OrderAmazonVdfDo::getPurchaseOrderNumber, val -> val, (val1, val2) -> val1));
        boolean isRetry = false;
        Map<Long, ShopDo> shopDoMap = new HashMap<>();
        for (Map.Entry<String, Long> entry : purchaseAndShopIdMap.entrySet()) {
            ShopDo shopDo = shopDoMap.get(entry.getValue());
            if (Objects.isNull(shopDo)) {
                shopDo = shopService.getById(entry.getValue());
                shopDoMap.put(entry.getValue(), shopDo);
            }
            //存在装箱单直接跳过
            OrderAmazonVdfDo one = poNoMatchOrderDo.get(entry.getKey());
            if (Objects.isNull(one) || StringUtils.isNotBlank(one.getPackingSlipUrl()) || Boolean.FALSE.equals(one.getIsPslipRequired())) {
                continue;
            }
            String body = null;
            try {
                try {
                    TimeUnit.MILLISECONDS.sleep(110);
                } catch (InterruptedException ignored) {

                }
                body = AmazonUtil.spAPidoGet(
                        GlobalConstants.AmazonSPAPIURL + "/vendor/directFulfillment/shipping/v1/packingSlips/" + entry.getKey(),
                        getAccessToken(shopDo),
                        getAwsSTSSessionToken(),
                        null
                );
            } catch (Exception e) {
                log.error("vdf获取装货单失败，原因：", e);
            }
            if (StringUtils.isBlank(body)) {
                continue;
            }
            JSONObject bodyJb = JSONObject.parseObject(body);
            if (bodyJb.isEmpty()) {
                continue;
            }
            if (bodyJb.get("errors") != null) {
                JSONArray errors = bodyJb.getJSONArray("errors");
                if (errors.size() > 0) {
                    log.error("vdf订单号：" + entry.getKey() + "获取装货单失败，原因：" + errors);
                } else {
                    log.error("vdf订单号：" + entry.getKey() + "获取装货单失败，原因：" + errors);
                }
            } else if (bodyJb.getJSONObject("payload").isEmpty()) {
                log.error("vdf订单号：" + entry.getKey() + "获取装货单为空");
                isRetry = true;
            } else {
                PackingSlip packingSlip = JSONObject.parseObject(
                        bodyJb.getJSONObject("payload").toString(),
                        PackingSlip.class
                );
                //装货单文件名
                String fileName = packingSlip.getPurchaseOrderNumber() + "-PackingSlip.pdf";
                ByteArrayInputStream bis = new ByteArrayInputStream(Base64.getDecoder().decode(packingSlip.getContent()));
                //上传文件到服务器
                Long fileId = fileService.uploadFileToFormalPath(bis, fileName);
                //获取文件url
                String fileUrl = fileService.getFilePath(fileId);
                this.lambdaUpdate()
                        .set(OrderAmazonVdfDo::getPackingSlipUrl, fileUrl)
                        .eq(OrderAmazonVdfDo::getPurchaseOrderNumber, packingSlip.getPurchaseOrderNumber())
                        .update();
            }
        }
        if (isRetry) {
            throw new BizException("vdf获取装货单失败，重试中...");
        }
    }

    @Override
    public String getAccessToken(ShopDo shopDo) throws Exception {
        String accessToken = (String) redisTemplate.opsForValue().get(AMZACCESSTOKEN + shopDo.getId());
        if (accessToken != null) {
            return accessToken;
        }
        String sessionTokenData = getAwsSTSSessionToken();
        accessToken = AmazonUtil.spGetToken(GlobalConstants.AmzSpClientId, GlobalConstants.AmzSpClientSecret, shopDo.getAmzSpLwa(), sessionTokenData);
        redisTemplate.opsForValue().set(AMZACCESSTOKEN + shopDo.getId(), accessToken, 3300, TimeUnit.SECONDS);
        return accessToken;
    }

    private String getAwsSTSSessionToken() {
        JSONObject jsonObject;
        jsonObject = (JSONObject) redisTemplate.opsForValue().get(STSSESSIONTOKEN);
        if (jsonObject != null) {
            GlobalConstants.accessSecrityKeySP = jsonObject.getString("AccessKeyId");
            GlobalConstants.secretSecrityKeySP = jsonObject.getString("SecretAccessKey");
            return jsonObject.getString("SessionToken");
        }
        Map<String, Object> parametersMap = new HashMap<>();
        parametersMap.put("Action", "AssumeRole");
        parametersMap.put("Version", "2011-06-15");
        parametersMap.put("RoleArn", "arn:aws:iam::975458911230:role/FBA-SP-API");
        parametersMap.put("RoleSessionName", "dingSession");
        String body = null;
        try {
            body = AmazonUtil.awsSTS("https://sts.us-west-2.amazonaws.com/", parametersMap);
            jsonObject = XmlUtils.xml2Json(body);
            JSONObject resultData = jsonObject.getJSONObject("AssumeRoleResponse").getJSONArray("AssumeRoleResult").getJSONObject(0).getJSONArray("Credentials").getJSONObject(0);
            redisTemplate.opsForValue().set(STSSESSIONTOKEN, resultData, 3600, TimeUnit.SECONDS);
            GlobalConstants.accessSecrityKeySP = resultData.getString("AccessKeyId");
            GlobalConstants.secretSecrityKeySP = resultData.getString("SecretAccessKey");
            String sessionToken = resultData.getString("SessionToken");
            return sessionToken;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public SingleResult pageInit(Long companyId) {
        HashMap<Object, Object> map = new HashMap<>(8);
        map.put("shopList", shopService.getShopList(companyId));
        map.put("companyList", companyService.getCompanyList());
        map.put("orderStatus", OrderStatus.getOrderStatusMap());
//        if (CollUtil.isEmpty(shipMethodStorage)) {
//            this.list(
//                    Wrappers.<OrderAmazonVdfDo>lambdaQuery()
//                            .select(OrderAmazonVdfDo::getShipMethod, OrderAmazonVdfDo::getShipMethodName)
//                            .isNotNull(OrderAmazonVdfDo::getShipMethod)
//                            .isNotNull(OrderAmazonVdfDo::getShipMethodName)
//                            .groupBy(OrderAmazonVdfDo::getShipMethod, OrderAmazonVdfDo::getShipMethodName)
//                            .last("limit 10000")
//            ).forEach(item -> shipMethodStorage.put(item.getShipMethod().split(",")[0], StrUtil.isEmpty(item.getShipMethodName().split(",")[0])?item.getShipMethod().split(",")[0]:item.getShipMethodName().split(",")[0]));
//        }
        map.put("shipMethodStorage", shipMethodStorage);
        return SingleResult.success(map);
    }

    @SneakyThrows(Exception.class)
    @Override
    public void exportShippingLabelVerticalA5Pdf(List<Long> ids, HttpServletResponse response) {
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition,illegalOrder,thirdPartyOrder");
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        //获取数据
        List<OrderAmazonVdfDo> dataList = this.lambdaQuery().select(OrderAmazonVdfDo::getId, OrderAmazonVdfDo::getPurchaseOrderNumber, OrderAmazonVdfDo::getLabelFileUrl, OrderAmazonVdfDo::getPackingSlipUrl).in(OrderAmazonVdfDo::getId, ids).list();
        //获取面单为空的订单
        List<OrderAmazonVdfDo> illegalOrder = dataList.stream().filter(orderAmazonVdfDo -> StringUtils.isBlank(orderAmazonVdfDo.getLabelFileUrl())).collect(Collectors.toList());
        List<OrderAmazonVdfDo> legalOrder = dataList.stream().filter(orderAmazonVdfDo -> StringUtils.isNotBlank(orderAmazonVdfDo.getLabelFileUrl())).collect(Collectors.toList());
        List<OrderAmazonVdfDo> existPackingSlipOrder = dataList.stream().filter(orderAmazonVdfDo -> StringUtils.isNotBlank(orderAmazonVdfDo.getPackingSlipUrl())).collect(Collectors.toList());
        JSONArray arr = new JSONArray();
        illegalOrder.forEach(i -> {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", i.getId());
            jsonObject.put("pno", i.getPurchaseOrderNumber());
            arr.add(jsonObject);
        });
        response.setHeader("illegalOrder", arr.toJSONString());
        if (CollUtil.isEmpty(legalOrder)) {
            return;
        }
        //统一获取商品的sku
        Map<String, String> skuMap = orderAmazonVdfItemService.list(Wrappers.<OrderAmazonVdfItemDo>lambdaQuery().in(OrderAmazonVdfItemDo::getPurchaseOrderNumber, legalOrder.stream().map(OrderAmazonVdfDo::getPurchaseOrderNumber).collect(Collectors.toList())).select(OrderAmazonVdfItemDo::getPurchaseOrderNumber, OrderAmazonVdfItemDo::getVendorProductIdentifier, OrderAmazonVdfItemDo::getItemSequenceNumber)).stream().distinct().collect(Collectors.toMap(key -> key.getPurchaseOrderNumber() + "-" + key.getItemSequenceNumber(), OrderAmazonVdfItemDo::getVendorProductIdentifier));
        OutputStream out;
        String fileName;
        String contentType;
        boolean isZip = false;
        //根据装箱单设置响应头
        if (CollUtil.isEmpty(existPackingSlipOrder)) {
            //返回pdf文件
            out = response.getOutputStream();
            fileName = "ShippingLabel.pdf";
            contentType = "application/pdf";
        } else {
            //返回压缩包
            out = new ByteArrayOutputStream();
            fileName = "ShippingLabel+PackingSlip.zip";
            contentType = "application/x-zip-compressed";
            isZip = true;
        }
        response.setHeader("Content-Type", contentType);
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        Document document = new Document(PageSize.A5);
        PdfWriter instance = PdfWriter.getInstance(document, out);
        //设置sku字体样式
        BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        document.open();
        PdfContentByte pdfContentByte = instance.getDirectContentUnder();

        //填充标签和sku
        for (OrderAmazonVdfDo orderAmazonVdfDo : legalOrder) {
            //获取发货标签文件url,一单多个发货标签采用隔开的字符串
            String fileUrl = orderAmazonVdfDo.getLabelFileUrl();
            String[] shippingLabelUrlArray = fileUrl.split(",");
            for (int i = 0; i < shippingLabelUrlArray.length; i++) {
                String shippingLabel = shippingLabelUrlArray[i];
                document.newPage();
                //获取sku
                String productSku = skuMap.get(orderAmazonVdfDo.getPurchaseOrderNumber() + "-" + (i + 1));
                if (StringUtils.isBlank(productSku)) {
                    productSku = skuMap.getOrDefault(orderAmazonVdfDo.getPurchaseOrderNumber() + "-1", "");
                }

                //添加图片
                Image image = getImage(shippingLabel);
                image.setAbsolutePosition(15, 10);
                pdfContentByte.addImage(image);

                //开始加载文本
                pdfContentByte.beginText();

                //添加sku
                //文字加粗,设置文本描边宽度
                pdfContentByte.setLineWidth(0.5);
                //设置文本为描边模式
                pdfContentByte.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
                //设置文本为中文、和字体大小
                pdfContentByte.setFontAndSize(bf, 14);
                //设置文本绝对坐标
                pdfContentByte.setTextMatrix(240, 45);
                //设置文本
                pdfContentByte.showText(productSku);

                //添加订单面单个数
                pdfContentByte.setLineWidth(0.5);
                pdfContentByte.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
                pdfContentByte.setFontAndSize(bf, 16);
                pdfContentByte.setTextMatrix(335, 110);
                pdfContentByte.showText((i + 1) + "/" + shippingLabelUrlArray.length);
                pdfContentByte.setLineWidth(0.5);
                pdfContentByte.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
                pdfContentByte.setFontAndSize(bf, 10);
                pdfContentByte.setTextMatrix(360, 110);
                pdfContentByte.showText("個口");

                //结束加载文本
                pdfContentByte.endText();
            }
        }
        document.close();
        if (isZip) {
            ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
            zos.setLevel(1);
            for (OrderAmazonVdfDo vdfDo : existPackingSlipOrder) {
                zos.putNextEntry(new ZipEntry(vdfDo.getPurchaseOrderNumber() + ".pdf"));
                zos.write(IOUtils.toByteArray(new URL(vdfDo.getPackingSlipUrl())));
                zos.closeEntry();
            }
            //发货标签
            zos.putNextEntry(new ZipEntry("ShippingLabel.pdf"));
            ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
            zos.write(bos.toByteArray());
            zos.closeEntry();
            zos.finish();
            zos.close();
        }
    }

    @Override
    public void updateOrderSendOut(String platformNumber) {
        dao.updateOrderSendOut(platformNumber);
    }

    @Override
    @SneakyThrows(Exception.class)
    public Map<String, Object> createShippingLabel(List<String> purchaseOrderNumberList, boolean isOverwrite) {
        List<OrderAmazonVdfDo> data = this.list(Wrappers.<OrderAmazonVdfDo>lambdaQuery().in(OrderAmazonVdfDo::getPurchaseOrderNumber, purchaseOrderNumberList));
        List<OrderAmazonVdfItemDo> itemData = orderAmazonVdfItemService.list(Wrappers.<OrderAmazonVdfItemDo>lambdaQuery().in(OrderAmazonVdfItemDo::getPurchaseOrderNumber, purchaseOrderNumberList));
        Map<String, List<OrderAmazonVdfItemDo>> itemMap = itemData.stream().collect(Collectors.groupingBy(OrderAmazonVdfItemDo::getPurchaseOrderNumber));
        //获取店铺信息
        Map<Long, ShopDo> shopDoMap = shopService.list().stream().collect(Collectors.toMap(ShopDo::getId, shopDo -> shopDo));
        //获取未生成发货标签的订单
        List<Long> legalOrder = data.stream().filter(orderAmazonVdfDo -> StringUtils.isNotBlank(orderAmazonVdfDo.getLabelFileUrl())).map(OrderAmazonVdfDo::getId).collect(Collectors.toList());
        List<String> illegalOrder = new ArrayList<>();
        //根据店铺进行发送创建面单
        Map<Long, List<OrderAmazonVdfDo>> orderByShopGroup = data.stream().filter(orderAmazonVdfDo -> StringUtils.isBlank(orderAmazonVdfDo.getLabelFileUrl()) || isOverwrite).collect(Collectors.groupingBy(OrderAmazonVdfDo::getShopId));
        //商品未进行维护列表
        List<String> productSpecificationInfoLoseList = new ArrayList<>();
        for (Map.Entry<Long, List<OrderAmazonVdfDo>> entry : orderByShopGroup.entrySet()) {
            Instant start = Instant.now();
            ShopDo shopDo = shopDoMap.get(entry.getKey());
            if (shopDo == null) {
                illegalOrder.addAll(entry.getValue().stream().map(OrderAmazonVdfDo::getPurchaseOrderNumber).collect(Collectors.toList()));
                continue;
            }
            List<ShippingLabelRequest> shippingLabelRequests = new ArrayList<>();
            //sku对应的商品规格
            Map<String, ProductSpecificationInfo> productSpecificationInfoMap = new HashMap<>();
            //订单对应的商品总数
            Map<String, Integer> totalQuantityMap = new HashMap<>();
            entry.getValue().forEach(orderAmazonVdfDo -> {
                String purchaseOrderNumber = orderAmazonVdfDo.getPurchaseOrderNumber();
                Long companyId = orderAmazonVdfDo.getCompanyId();
                //此订单的商品重量
                AtomicReference<Float> totalWeight = new AtomicReference<>(0f);
                //订单商品列表
                List<OrderAmazonVdfItemDo> vdfItemDoList = itemMap.get(purchaseOrderNumber);
                //预先准备数据
                vdfItemDoList.forEach(item -> {
                    String sku = item.getVendorProductIdentifier();
                    //获取商品规格，包括长宽高重量
                    ProductSpecificationInfo productSpecificationInfo = productSpecificationInfoMap.computeIfAbsent(sku, key -> {
                        Long productId = productInfoService.getProductIdNoThrow(key, companyId);
                        if (productId.equals(0L)) {
                            return ProductSpecificationInfo.builder().length(0f).width(0f).height(0f).weight(0f).build();
                        } else {
                            ProductInfoDo productInfoDo = productInfoService.getOne(Wrappers.<ProductInfoDo>lambdaQuery().select(ProductInfoDo::getId, ProductInfoDo::getLength, ProductInfoDo::getWidth, ProductInfoDo::getHeight, ProductInfoDo::getWeight).eq(ProductInfoDo::getId, productId));
                            return ProductSpecificationInfo.builder().length(productInfoDo.getLength()).width(productInfoDo.getWidth()).height(productInfoDo.getHeight()).weight(productInfoDo.getWeight()).build();
                        }
                    });
                    //计算总重量
                    totalWeight.updateAndGet(v -> v + item.getOrderedQuantity() * (productSpecificationInfo.getWeight()));
                    //计算商品总数量
                    totalQuantityMap.put(purchaseOrderNumber, totalQuantityMap.getOrDefault(purchaseOrderNumber, 0) + item.getOrderedQuantity());
                });
                //请求参数
                ShippingLabelRequest labelRequest = new ShippingLabelRequest();
                //超过15公斤分包
                if (totalWeight.get() > 0.1) {
                    int orderProductNum = totalQuantityMap.get(purchaseOrderNumber);
                    //一件商品不用分包
                    if (orderProductNum > 1) {
                        //包裹唯一标识符后缀序号，从1开始，订单分出多少包裹序号就是多少
                        AtomicInteger containerIdCount = new AtomicInteger(1);
                        //包裹列表
                        List<Container> containers = new ArrayList<>();
                        //包裹内商品列表
                        List<PackedItem> packedItems;
                        for (int i = 0; i < vdfItemDoList.size(); i++) {
                            OrderAmazonVdfItemDo item = vdfItemDoList.get(i);
                            String sku = item.getVendorProductIdentifier();
                            //获取商品规格
                            ProductSpecificationInfo productSpecificationInfo = productSpecificationInfoMap.getOrDefault(sku, ProductSpecificationInfo.builder().length(0f).width(0f).height(0f).weight(0f).build());
                            //判断商品规格信息是否完整
                            if (productSpecificationInfo.getLength() + productSpecificationInfo.getWidth() + productSpecificationInfo.getHeight() + productSpecificationInfo.getWeight() == 0) {
                                productSpecificationInfoLoseList.add(sku);
                                //只要有一个商品规格信息不完整，就自定义不了分包，所以直接跳出
                                break;
                            }
                            //商品重量
                            Float weight = productSpecificationInfo.getWeight();
                            //此商品总数
                            Integer productTotalQuantity = item.getOrderedQuantity();
                            //每个商品都是一个包裹
                            for (int j = 0; j < productTotalQuantity; j++) {
                                PackedItem packedItem = PackedItem.builder().itemSequenceNumber(i + 1).buyerProductIdentifier(item.getBuyerProductIdentifier()).vendorProductIdentifier(sku).packedQuantity(PackedItemQuantity.builder().amount(productTotalQuantity).unitOfMeasure("Each").build()).build();
                                packedItems = Collections.singletonList(packedItem);
                                Container container = new Container();
                                //容器长宽高，这里就是商品长宽高 一件商品一个包的情况
                                container.setDimensions(Dimensions.builder().length(BigDecimal.valueOf(productSpecificationInfo.getLength())).width(BigDecimal.valueOf(productSpecificationInfo.getWidth())).height(BigDecimal.valueOf(productSpecificationInfo.getHeight())).unitOfMeasure(DimensionsUnit.CM).build());
                                container.setContainerType(ContainerType.carton);
                                //容器唯一标识固定为po号加容器序号
                                container.setContainerIdentifier(item.getPurchaseOrderNumber() + "-" + containerIdCount.getAndIncrement());
                                //基于sku的容器序号（每个sku都是从1开始）
                                container.setContainerSequenceNumber(j + 1);
                                container.setWeight(Weight.builder().unitOfMeasure(WeightUnit.KG).value(BigDecimal.valueOf(weight)).build());
                                container.setPackedItems(packedItems);
                                containers.add(container);
                            }
                            // packedCount.getAndIncrement();
                            // containerCount.set(1);
                        }
                        //存在分包并且所有商品的规格完整就添加分包信息进行创建面单
                        if (CollUtil.isNotEmpty(containers) && containers.size() == orderProductNum) {
                            labelRequest.setContainers(containers);
                        }
                    }
                }
                labelRequest.setPurchaseOrderNumber(orderAmazonVdfDo.getPurchaseOrderNumber());
                labelRequest.setShipFromParty(JSONObject.parseObject(orderAmazonVdfDo.getShipFromParty(), PartyIdentification.class));
                labelRequest.setSellingParty(JSONObject.parseObject(orderAmazonVdfDo.getSellingParty(), PartyIdentification.class));
                shippingLabelRequests.add(labelRequest);
            });
            Map<String, Object> parametersMap = new HashMap<>(2);
            parametersMap.put("shippingLabelRequests", shippingLabelRequests);
            String body = null;
            try {
                Instant end = Instant.now();
                long timeInterval = Duration.between(start, end).toMillis();
                if (timeInterval < 105) {
                    TimeUnit.MILLISECONDS.sleep(100 - timeInterval);
                }
                body = AmazonUtil.spAPidoPOST(GlobalConstants.AmazonSPAPIURL + "/vendor/directFulfillment/shipping/v1/shippingLabels", getAccessToken(shopDo), getAwsSTSSessionToken(), parametersMap, JSON.toJSONString(parametersMap));
                //到这一步说明接口调用成功了 把接口执行条件的开始时间和结束时间存放在同步表中
            } catch (Exception e) {
                log.error("vdf创建发货标签失败，原因：", e);
            }
            if (StringUtils.isBlank(body)) {
                continue;
            }
            JSONObject bodyJb = JSONObject.parseObject(body);
            if (bodyJb.isEmpty()) {
                continue;
            }
            if (bodyJb.get("errors") != null) {
                JSONArray errors = bodyJb.getJSONArray("errors");
                if (errors.size() > 0) {
                    log.error("vdf创建发货标签信息失败，原因：" + errors);
                } else {
                    log.error("vdf创建发货标签信息失败，原因：" + errors);
                }
                illegalOrder.addAll(entry.getValue().stream().map(OrderAmazonVdfDo::getPurchaseOrderNumber).collect(Collectors.toList()));
            } else if (bodyJb.getJSONObject("payload").isEmpty()) {
                log.error("vdf创建发货标签信息为空");
                illegalOrder.addAll(entry.getValue().stream().map(OrderAmazonVdfDo::getPurchaseOrderNumber).collect(Collectors.toList()));
            } else {
                Map<String, Long> map = new HashMap<>();
                entry.getValue().forEach(orderAmazonVdfDo -> map.put(orderAmazonVdfDo.getPurchaseOrderNumber(), entry.getKey()));
                //获取发货标签
                CompletableFuture.runAsync(() -> {
                    //自定义包裹获取发货标签需等待创建发货标签完成
                    if (isOverwrite) {
                        /*if (!bodyJb.getJSONObject("payload").getString("transactionId").isEmpty()) {
                            try {
                                this.getCreatLabelsStatus(shopDo, bodyJb.getJSONObject("payload").getString("transactionId"));
                                this.getVdfShippingLabel(map, false, true);
                            } catch (RuntimeException e) {
                                e.printStackTrace();
                            }
                        }*/
                        delayTaskService.addTask(new GetShippingLabelDelay(SysConstant.VDF_SHIPPING_LABEL_DELAY_TIME, map, String.valueOf(DateUtil.current()), LocalDateTime.now()));
                    } else {
                        try {
                            this.getVdfShippingLabel(map, false, false);
                        } catch (RuntimeException e) {
                            e.printStackTrace();
                        }
                    }
                }, threadPoolExecutor);
                legalOrder.addAll(entry.getValue().stream().map(OrderAmazonVdfDo::getId).collect(Collectors.toList()));
            }
        }
        HashMap<String, Object> map = new HashMap<>(4);
        //legalOrder合法vdf订单（创建成功，返回vdf订单id）
        map.put("legalOrder", legalOrder);
        // illegalOrder非法vdf订单（创建失败，返回采购订单号）
        map.put("illegalOrder", illegalOrder);
        if (CollUtil.isNotEmpty(productSpecificationInfoLoseList)) {
            // productSpecificationInfoLoseList商品规格信息缺失
            map.put("productSpecificationInfoLoseList", productSpecificationInfoLoseList);
        }
        return map;
    }

    @Override
    public Map<String, Object> createShippingLabelV2(List<String> purchaseOrderNumberList, boolean isOverwrite) {
        List<OrderAmazonVdfDo> data = this.list(
                Wrappers.<OrderAmazonVdfDo>lambdaQuery()
                        .in(OrderAmazonVdfDo::getPurchaseOrderNumber, purchaseOrderNumberList)
        );
        List<OrderAmazonVdfItemDo> itemData = orderAmazonVdfItemService.list(
                Wrappers.<OrderAmazonVdfItemDo>lambdaQuery()
                        .in(OrderAmazonVdfItemDo::getPurchaseOrderNumber, purchaseOrderNumberList)
        );
        Map<String, List<OrderAmazonVdfItemDo>> itemMap = itemData.stream()
                .collect(Collectors.groupingBy(OrderAmazonVdfItemDo::getPurchaseOrderNumber));
        //获取店铺信息
        Map<Long, ShopDo> shopDoMap = shopService.list().stream()
                .collect(Collectors.toMap(ShopDo::getId, shopDo -> shopDo));
        //获取未生成发货标签的订单
        List<Long> legalOrder = data.stream()
                .filter(orderAmazonVdfDo -> StringUtils.isNotBlank(orderAmazonVdfDo.getLabelFileUrl()))
                .map(OrderAmazonVdfDo::getId)
                .collect(Collectors.toList());
        List<String> illegalOrder = new ArrayList<>();
        //根据店铺进行发送创建面单
        Map<Long, List<OrderAmazonVdfDo>> orderByShopGroup = data.stream()
                .filter(orderAmazonVdfDo -> StringUtils.isBlank(orderAmazonVdfDo.getLabelFileUrl()) || isOverwrite)
                .collect(Collectors.groupingBy(OrderAmazonVdfDo::getShopId));
        //商品未进行维护列表
        List<String> productSpecificationInfoLoseList = new ArrayList<>();
        for (Map.Entry<Long, List<OrderAmazonVdfDo>> entry : orderByShopGroup.entrySet()) {
            Instant start = Instant.now();
            ShopDo shopDo = shopDoMap.get(entry.getKey());
            if (shopDo == null) {
                illegalOrder.addAll(entry.getValue().stream()
                        .map(OrderAmazonVdfDo::getPurchaseOrderNumber)
                        .collect(Collectors.toList()));
                continue;
            }
            List<ShippingLabelRequest> shippingLabelRequests = new ArrayList<>();
            //sku对应的商品规格
            Map<String, ProductSpecificationInfo> productSpecificationInfoMap = new HashMap<>();
            //订单对应的商品总数
            Map<String, Integer> totalQuantityMap = new HashMap<>();
            entry.getValue().forEach(orderAmazonVdfDo -> {
                String purchaseOrderNumber = orderAmazonVdfDo.getPurchaseOrderNumber();
                Long companyId = orderAmazonVdfDo.getCompanyId();
                //此订单的商品重量
                AtomicReference<Float> totalWeight = new AtomicReference<>(0f);
                //订单商品列表
                List<OrderAmazonVdfItemDo> vdfItemDoList = itemMap.get(purchaseOrderNumber);
                //预先准备数据
                vdfItemDoList.forEach(item -> {
                    String sku = item.getVendorProductIdentifier();
                    //获取商品规格，包括长宽高重量
                    ProductSpecificationInfo productSpecificationInfo = productSpecificationInfoMap.computeIfAbsent(sku, key -> {
                        Long productId = productInfoService.getProductIdNoThrow(key, companyId);
                        if (productId.equals(0L)) {
                            return ProductSpecificationInfo.builder().build();
                        } else {
                            ProductInfoDo productInfoDo = productInfoService.getOne(
                                    Wrappers.<ProductInfoDo>lambdaQuery()
                                            .select(
                                                    ProductInfoDo::getId,
                                                    ProductInfoDo::getLength,
                                                    ProductInfoDo::getWidth,
                                                    ProductInfoDo::getHeight,
                                                    ProductInfoDo::getWeight
                                            )
                                            .eq(ProductInfoDo::getId, productId)
                            );
                            return ProductSpecificationInfo.builder()
                                    .length(productInfoDo.getLength())
                                    .width(productInfoDo.getWidth())
                                    .height(productInfoDo.getHeight())
                                    .weight(productInfoDo.getWeight())
                                    .build();
                        }
                    });
                    //计算总重量
                    totalWeight.updateAndGet(v -> v + item.getOrderedQuantity() * (productSpecificationInfo.getWeight()));
                    //计算商品总数量
                    totalQuantityMap.put(
                            purchaseOrderNumber,
                            totalQuantityMap.getOrDefault(purchaseOrderNumber, 0) + item.getOrderedQuantity()
                    );
                });
                //请求参数
                ShippingLabelRequest labelRequest = new ShippingLabelRequest();
                //超过15公斤分包
                if (totalWeight.get() > 0.1) {
                    int orderProductNum = totalQuantityMap.get(purchaseOrderNumber);
                    //一件商品不用分包
                    if (orderProductNum > 1) {
                        //包裹唯一标识符后缀序号，从1开始，订单分出多少包裹序号就是多少
                        AtomicInteger containerIdCount = new AtomicInteger(1);
                        //包裹列表
                        List<Container> containers = new ArrayList<>();
                        //包裹内商品列表
                        List<PackedItem> packedItems;
                        for (int i = 0; i < vdfItemDoList.size(); i++) {
                            OrderAmazonVdfItemDo item = vdfItemDoList.get(i);
                            String sku = item.getVendorProductIdentifier();
                            //获取商品规格
                            ProductSpecificationInfo productSpecificationInfo = productSpecificationInfoMap.getOrDefault(
                                    sku,
                                    ProductSpecificationInfo.builder().build()
                            );
                            //判断商品规格信息是否完整
                            if (productSpecificationInfo.getLength() + productSpecificationInfo.getWidth() + productSpecificationInfo.getHeight() + productSpecificationInfo.getWeight() == 0) {
                                productSpecificationInfoLoseList.add(sku);
                                //只要有一个商品规格信息不完整，就自定义不了分包，所以直接跳出
                                break;
                            }
                            //商品重量
                            Float weight = productSpecificationInfo.getWeight();
                            //此商品总数
                            Integer productTotalQuantity = item.getOrderedQuantity();
                            //每个商品都是一个包裹
                            for (int j = 0; j < productTotalQuantity; j++) {
                                PackedItem packedItem = PackedItem.builder()
                                        .itemSequenceNumber(i + 1)
                                        .buyerProductIdentifier(item.getBuyerProductIdentifier())
                                        .vendorProductIdentifier(sku)
                                        .packedQuantity(
                                                PackedItemQuantity.builder()
                                                        .amount(productTotalQuantity)
                                                        .unitOfMeasure("Each")
                                                        .build()
                                        )
                                        .build();
                                packedItems = Collections.singletonList(packedItem);
                                Container container = new Container();
                                //容器长宽高，这里就是商品长宽高 一件商品一个包的情况
                                container.setDimensions(
                                        Dimensions.builder()
                                                .length(BigDecimal.valueOf(productSpecificationInfo.getLength()))
                                                .width(BigDecimal.valueOf(productSpecificationInfo.getWidth()))
                                                .height(BigDecimal.valueOf(productSpecificationInfo.getHeight()))
                                                .unitOfMeasure(DimensionsUnit.CM)
                                                .build()
                                );
                                container.setContainerType(ContainerType.carton);
                                //容器唯一标识固定为po号加容器序号
                                container.setContainerIdentifier(item.getPurchaseOrderNumber() + "-" + containerIdCount.getAndIncrement());
                                //基于sku的容器序号（每个sku都是从1开始）
                                container.setContainerSequenceNumber(j + 1);
                                container.setWeight(
                                        Weight.builder()
                                                .unitOfMeasure(WeightUnit.KG)
                                                .value(BigDecimal.valueOf(weight))
                                                .build()
                                );
                                container.setPackedItems(packedItems);
                                containers.add(container);
                            }
                        }
                        //存在分包并且所有商品的规格完整就添加分包信息进行创建面单
                        if (CollUtil.isNotEmpty(containers) && containers.size() == orderProductNum) {
                            labelRequest.setContainers(containers);
                        }
                    }
                }
                labelRequest.setPurchaseOrderNumber(orderAmazonVdfDo.getPurchaseOrderNumber());
                labelRequest.setShipFromParty(JSONObject.parseObject(orderAmazonVdfDo.getShipFromParty(), PartyIdentification.class));
                labelRequest.setSellingParty(JSONObject.parseObject(orderAmazonVdfDo.getSellingParty(), PartyIdentification.class));
                shippingLabelRequests.add(labelRequest);
            });
            Map<String, Object> parametersMap = new HashMap<>(2);
            parametersMap.put("shippingLabelRequests", shippingLabelRequests);
            String body = null;
            try {
                Instant end = Instant.now();
                long timeInterval = Duration.between(start, end).toMillis();
                if (timeInterval < 105) {
                    TimeUnit.MILLISECONDS.sleep(100 - timeInterval);
                }
                body = AmazonUtil.spAPidoPOST(
                        GlobalConstants.AmazonSPAPIURL + "/vendor/directFulfillment/shipping/v1/shippingLabels",
                        getAccessToken(shopDo),
                        getAwsSTSSessionToken(),
                        parametersMap,
                        JSON.toJSONString(parametersMap)
                );
                //到这一步说明接口调用成功了 把接口执行条件的开始时间和结束时间存放在同步表中
            } catch (Exception e) {
                log.error("vdf创建发货标签失败，原因：", e);
            }
            if (StringUtils.isBlank(body)) {
                continue;
            }
            JSONObject bodyJb = JSONObject.parseObject(body);
            if (bodyJb.isEmpty()) {
                continue;
            }
            if (bodyJb.get("errors") != null) {
                JSONArray errors = bodyJb.getJSONArray("errors");
                if (errors.size() > 0) {
                    log.error("vdf创建发货标签信息失败，原因：" + errors);
                } else {
                    log.error("vdf创建发货标签信息失败，原因：" + errors);
                }
                illegalOrder.addAll(entry.getValue().stream().map(OrderAmazonVdfDo::getPurchaseOrderNumber).collect(Collectors.toList()));
            } else if (bodyJb.getJSONObject("payload").isEmpty()) {
                log.error("vdf创建发货标签信息为空");
                illegalOrder.addAll(entry.getValue().stream().map(OrderAmazonVdfDo::getPurchaseOrderNumber).collect(Collectors.toList()));
            } else {
                Map<String, Long> map = new HashMap<>();
                entry.getValue().forEach(orderAmazonVdfDo -> map.put(orderAmazonVdfDo.getPurchaseOrderNumber(), entry.getKey()));
                //获取发货标签
                CompletableFuture.runAsync(() -> {
                    //自定义包裹获取发货标签需等待创建发货标签完成
                    if (isOverwrite) {
                        /*if (!bodyJb.getJSONObject("payload").getString("transactionId").isEmpty()) {
                            try {
                                this.getCreatLabelsStatus(shopDo, bodyJb.getJSONObject("payload").getString("transactionId"));
                                this.getVdfShippingLabel(map, false, true);
                            } catch (RuntimeException e) {
                                e.printStackTrace();
                            }
                        }*/
                        delayTaskService.addTask(new GetShippingLabelDelay(
                                SysConstant.VDF_SHIPPING_LABEL_DELAY_TIME,
                                map,
                                String.valueOf(DateUtil.current()),
                                LocalDateTime.now()
                        ));
                    } else {
                        try {
                            this.getVdfShippingLabel(map, false, false);
                        } catch (RuntimeException e) {
                            e.printStackTrace();
                        }
                    }
                }, threadPoolExecutor);
                legalOrder.addAll(entry.getValue().stream().map(OrderAmazonVdfDo::getId).collect(Collectors.toList()));
            }
        }
        HashMap<String, Object> map = new HashMap<>(4);
        //legalOrder合法vdf订单（创建成功，返回vdf订单id）
        map.put("legalOrder", legalOrder);
        // illegalOrder非法vdf订单（创建失败，返回采购订单号）
        map.put("illegalOrder", illegalOrder);
        if (CollUtil.isNotEmpty(productSpecificationInfoLoseList)) {
            // productSpecificationInfoLoseList商品规格信息缺失
            map.put("productSpecificationInfoLoseList", productSpecificationInfoLoseList);
        }
        return map;
    }

    @Override
    public OrderAmazonVdfDo addByOrderOutput(OpenApiOrderOutputAddReq req, Long companyId, Long shopId) {
        OrderAmazonVdfDo vdfDo = new OrderAmazonVdfDo();
        vdfDo.setCompanyId(companyId);
        vdfDo.setShopId(shopId);
        vdfDo.setPurchaseOrderNumber(req.getDfOrder().getDfPo());
        vdfDo.setShipPostalCode(req.getPostCode());
        vdfDo.setShipAddress1(req.getAddress());
        vdfDo.setShipName(req.getReceiverName());
        OpenApiDFOrderReq dfOrder = req.getDfOrder();
        if (dfOrder != null) {
            vdfDo.setShipMethod(dfOrder.getShipMethod());
            vdfDo.setPackingSlipUrl(req.getDfOrder().getPackingSlipUrl());
            if (dfOrder.getShippingLabelUrl() != null && !dfOrder.getShippingLabelUrl().isEmpty()) {
                StringBuilder trackNumberBuilder = new StringBuilder();
                StringBuilder labelFileBuilder = new StringBuilder();
                for (String s : dfOrder.getShippingLabelUrl().keySet()) {
                    if (trackNumberBuilder.length() > 0) trackNumberBuilder.append(",");
                    trackNumberBuilder.append(s);
                    if (labelFileBuilder.length() > 0) labelFileBuilder.append(",");
                    labelFileBuilder.append(dfOrder.getShippingLabelUrl().get(s).stream().collect(Collectors.joining(",")));
                }
                vdfDo.setTrackingNumber(trackNumberBuilder.toString());
                vdfDo.setLabelFileUrl(labelFileBuilder.toString());
            }
        }
        save(vdfDo);
        List<OrderAmazonVdfItemDo> itemDoList = new ArrayList<>();
        for (int i = 0; i < req.getProductList().size(); i++) {
            OpenApiOrderOutputProductAddReq openApiOrderOutputProductAddReq = req.getProductList().get(i);
            OrderAmazonVdfItemDo itemDo = new OrderAmazonVdfItemDo();
            itemDo.setPurchaseOrderNumber(vdfDo.getPurchaseOrderNumber());
            itemDo.setItemSequenceNumber(i + 1);
            itemDo.setVendorProductIdentifier(openApiOrderOutputProductAddReq.getCommoditySku());
            itemDo.setOrderedQuantity(openApiOrderOutputProductAddReq.getCount());
            itemDoList.add(itemDo);
        }
        orderAmazonVdfItemService.insertBatch(itemDoList);
        return vdfDo;
    }

    @Override
    public JSONArray refreshShippingLabel(String purchaseOrderNumber) {
        OrderAmazonVdfDo one = baseMapper.selectOne(Wrappers.<OrderAmazonVdfDo>lambdaQuery().eq(OrderAmazonVdfDo::getPurchaseOrderNumber, purchaseOrderNumber));
        Long shopId = one.getShopId();
        if (Objects.isNull(shopId)) {
            return null;
        }
        HashMap<String, Long> data = new HashMap<>();
        data.put(purchaseOrderNumber, shopId);
        this.getVdfShippingLabel(data, false, true);
        OrderAmazonVdfDo two = baseMapper.selectOne(Wrappers.<OrderAmazonVdfDo>lambdaQuery().eq(OrderAmazonVdfDo::getPurchaseOrderNumber, purchaseOrderNumber));
        String trackingNumber = two.getTrackingNumber();
        String labelFileUrl = two.getLabelFileUrl();
        JSONArray arr = new JSONArray();
        if (StringUtils.isNotBlank(trackingNumber) && StringUtils.isNotBlank(labelFileUrl)) {
            String[] t1 = trackingNumber.split(",");
            String[] t2 = labelFileUrl.split(",");
            for (int i = 0; i < t1.length; i++) {
                JSONObject obj = new JSONObject();
                obj.put("trackingNumber", t1[i]);
                obj.put("img", t2[i]);
                arr.add(obj);
            }
            return arr;
        }
        return null;
    }

    /**
     * 计算包裹长宽高
     *
     * @param packedSkuQuantity           包裹内的商品数量  key：sku  value：数量
     * @param productSpecificationInfoMap 商品规格信息  key：sku  value：商品规格信息
     * @return 包裹长宽高
     */
    private Dimensions calculateContainerDimensions(Map<String, Integer> packedSkuQuantity, Map<String, ProductSpecificationInfo> productSpecificationInfoMap) {
        //计算包裹长宽高
        Map<String, Float> dimensionsMap = new HashMap<>(8);
        packedSkuQuantity.forEach((sku, quantity) -> {
            //获取sku的规格信息
            ProductSpecificationInfo productSpecificationInfo = productSpecificationInfoMap.get(sku);
            if (productSpecificationInfo.getLength() > dimensionsMap.getOrDefault("length", 0f)) {
                dimensionsMap.put("length", productSpecificationInfo.getLength());
            }
            if (productSpecificationInfo.getWidth() > dimensionsMap.getOrDefault("width", 0f)) {
                dimensionsMap.put("width", productSpecificationInfo.getWidth());
            }
            dimensionsMap.put("height", dimensionsMap.getOrDefault("height", 0f) + productSpecificationInfo.getHeight() * quantity);
        });
        //对包裹长宽高进行排序
        List<Float> size = dimensionsMap.values().stream().sorted().collect(Collectors.toList());
        return Dimensions.builder().length(BigDecimal.valueOf(size.get(2))).width(BigDecimal.valueOf(size.get(1))).height(BigDecimal.valueOf(size.get(0))).unitOfMeasure(DimensionsUnit.CM).build();
    }

    /**
     * 获取创建发货标签的状态
     * 创建自定义包裹的面单需要时间较长（一分钟左右），所以需要重试
     *
     * @param shopDo        店铺信息
     * @param transactionId 事务id
     */
    public void getCreatLabelsStatus(ShopDo shopDo, String transactionId) throws RuntimeException {
        String body;
        String status;
        int retryCount = 0;
        while (retryCount < 6) {
            retryCount++;
            try {
                Thread.sleep(20000);
            } catch (InterruptedException ignored) {
            }
            try {
                body = AmazonUtil.spAPidoGet(GlobalConstants.AmazonSPAPIURL + "/vendor/directFulfillment/transactions/v1/transactions/" + transactionId, getAccessToken(shopDo), getAwsSTSSessionToken(), null);
                JSONObject bodyJb = JSONObject.parseObject(body);
                if (!bodyJb.getJSONObject("payload").isEmpty()) {
                    status = bodyJb.getJSONObject("payload").getJSONObject("transactionStatus").getString("status");
                    if ("Success".equals(status)) {
                        return;
                    }
                }
            } catch (Exception ignored) {
            }
        }
    }


    @Override
    public void getCustomerInvoices(Long shopId, Date beforeDate, Date afterDate) {
        ShopDo shopDo = shopService.getById(shopId);
        String nextToken = "";
        do {
            Map<String, Object> parametersMap = new HashMap<>(16);

            if (StringUtils.isNotBlank(nextToken)) {
                parametersMap.put("nextToken", nextToken);
            }
            parametersMap.put("limit", 100);
            parametersMap.put("createdAfter", new SimpleDateFormat(GlobalConstants.TIME_FORMAT_STR).format(beforeDate));
            //在查询时间上加一天
            parametersMap.put("createdBefore", new SimpleDateFormat(GlobalConstants.TIME_FORMAT_STR).format(new Date(afterDate.getTime() + 24 * 60 * 60 * 1000 - 1)));

            //发货仓库的供应商仓库标识符。如果未指定，则结果将包含所有仓库的订单 todo 先不做
//                parametersMap.put("shipFromPartyId", "A2QD8CZ5OYH9Q2");
            //按订单创建日期排序
            parametersMap.put("sortOrder", SortOrder.ASC.getValue());

            String body = null;
            try {
                body = AmazonUtil.spAPidoGet(GlobalConstants.AmazonSPAPIURL + "/vendor/directFulfillment/shipping/v1/customerInvoices", getAccessToken(shopDo), getAwsSTSSessionToken(), parametersMap);
                //到这一步说明接口调用成功了 把接口执行条件的开始时间和结束时间存放在同步表中
            } catch (Exception e) {
                e.printStackTrace();
                log.error("同步vdf Order失败，原因：", e);
            }
            if (StringUtils.isBlank(body)) {
                continue;
            }
            System.out.println(body);
            JSONObject bodyJb = JSONObject.parseObject(body);
            //循环调接口 如果返回结果为空 跳过继续下一条
            if (bodyJb.isEmpty()) {
                continue;
            }
            if (bodyJb.get("errors") != null) {
                JSONArray errors = bodyJb.getJSONArray("errors");
                if (errors.size() > 0) {
                    log.error("店铺：" + shopDo.getShopName() + "同步vdf订单失败，原因：" + errors);
                } else {
                    log.error("店铺：" + shopDo.getShopName() + "同步vdf订单失败，原因：未知");
                }
            } else {
                List<CustomerInvoiceEntity> customerInvoiceList = JSONArray.parseArray(bodyJb.getJSONObject("payload").getString("customerInvoices"), CustomerInvoiceEntity.class);
                this.customerInvoicesHandler(customerInvoiceList);
            }
            if (bodyJb.getJSONObject("payload") != null && bodyJb.getJSONObject("payload").getJSONObject("pagination") != null) {
                nextToken = bodyJb.getJSONObject("payload").getJSONObject("pagination").getString("nextToken");
            } else {
                nextToken = null;
            }
        } while (StringUtils.isNotBlank(nextToken));
    }

    @Async("taskExecutor")
    public void customerInvoicesHandler(List<CustomerInvoiceEntity> customerInvoiceList) {
        if (CollUtil.isEmpty(customerInvoiceList)) {
            return;
        }
        customerInvoiceList.forEach(customerInvoiceEntity -> {
            //发票文件名
            String fileName = customerInvoiceEntity.getPurchaseOrderNumber() + "Invoice.png";
            //base64转文件流
            InputStream inputStream;
            try {
                inputStream = Base64AndFileStreamUtil.base64ToFile(customerInvoiceEntity.getContent(), filePathTemp, fileName);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            //上传文件到服务器
            /*Long fileId = fileService.uploadTempFile(fileName, inputStream, 1L);
            //将临时文件转移到真正的存储路径
            fileService.uploadFile(fileId);*/
            Long fileId = fileService.uploadFileToFormalPath(inputStream, fileName);
            //获取文件url
            String fileUrl = fileService.getFilePath(fileId);
            //更新数据库
            this.lambdaUpdate().eq(OrderAmazonVdfDo::getPurchaseOrderNumber, customerInvoiceEntity.getPurchaseOrderNumber()).set(OrderAmazonVdfDo::getInvoiceFileUrl, fileUrl).update();
        });
    }

    /**
     * 创建发货标签的图片实例
     *
     * @param path 图片url或本地路径
     * @return 图片实例
     */
    private Image getImage(String path) {
        Image img;
        try {
            img = Image.getInstance(path);
        } catch (BadElementException | IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        img.setAlignment(Image.LEFT | Image.TEXTWRAP);
        img.setBorder(Image.BOX);
        img.setBorderWidth(1);
        img.setBorderColor(BaseColor.WHITE);
        //大小
        img.scaleToFit(726, 578);
        return img;
    }

    @Override
    public SingleResult markSendOut(List<Long> ids, Long userId) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new BizException(SysConstant.PLS_CHOOSE_ORDER);
        }
        for (Long id : ids) {
            OrderAmazonVdfDo orderAmazonDo = this.baseMapper.selectById(id);
//            if (orderAmazonDo.getIsSendOut() == 0) {
            orderAmazonDo.setIsSendOut(1);
            this.baseMapper.updateById(orderAmazonDo);
            operateRecordDao.operateAddRecord(SysConstant.OPERATE_MARK_SEND, orderAmazonDo.getId(), userId, 10);
//            }
        }
        return SingleResult.success();
    }

    @Override
    public SingleResult sendOut(String[] orderids, Long userId, Long companyId, boolean b) {
        List<OrderOutputAddReq> orderOutputAddReqList = new ArrayList<>();
        List<String> failOrders = new ArrayList<>();
        List<OrderAmazonVdfDo> orderAmazonDos = baseMapper.selectBatchIds(Arrays.asList(orderids));
        for (OrderAmazonVdfDo orderAmazonDo : orderAmazonDos) {
            if (orderAmazonDo == null) {
                throw new BizException(SysConstant.Error_Data_NotExist);
            }
//            LambdaQueryWrapper<OrderAmazonVdfItemDo> wrapper = new LambdaQueryWrapper<>();
//            wrapper.eq(OrderAmazonVdfItemDo::getPurchaseOrderNumber, orderAmazonDo.getPurchaseOrderNumber());
            List<OrderAmazonVdfItemDo> itemsDoList = orderAmazonVdfItemService.list(Wrappers.<OrderAmazonVdfItemDo>lambdaQuery().eq(OrderAmazonVdfItemDo::getPurchaseOrderNumber, orderAmazonDo.getPurchaseOrderNumber()));
            //订单
            OrderOutputAddReq res = new OrderOutputAddReq();
            res.setPlatform("vdf");
            res.setPlatformNumber(orderAmazonDo.getId() + "");
            res.setSendDate(new Date());
            res.setShopId(orderAmazonDo.getShopId());
            res.setCompanyId(orderAmazonDo.getCompanyId());
            res.setOrderNo(orderAmazonDo.getPurchaseOrderNumber());
            res.setReceiverName(orderAmazonDo.getShipName() + " 様");
            res.setTelPhone(orderAmazonDo.getShipPhone());
            res.setPostCode(orderAmazonDo.getShipPostalCode());
            res.setArea(orderAmazonDo.getShipStateOrRegion());
            res.setAddress(orderAmazonDo.getShipAddress1());
            if ("YAMATO_LTL".equals(orderAmazonDo.getShipMethod()) ||
                    "YAMATO_OVERSIZE".equals(orderAmazonDo.getShipMethod())) {
                // res.setTips(StringUtils.isNotBlank(orderAmazonDo.getShipMethodName())?orderAmazonDo.getShipMethodName():orderAmazonDo.getShipMethod());
                res.setTrackId(DicBusinessItemConstant.yamatoExpressYHC);
            } else {
                res.setTrackId(DicBusinessItemConstant.yamatoExpressA);
            }
            if (StringUtils.isNotBlank(orderAmazonDo.getPackingSlipUrl())) {
                res.setTips("需要受领书");
                res.setTrackId(DicBusinessItemConstant.yamatoExpressSLS);
            }
            res.setPackingSlipUrl(orderAmazonDo.getPackingSlipUrl());
            if (orderAmazonDo.getPromisedDeliveryDate() != null && orderAmazonDo.getIsScheduledDeliveryShipment()) {
                try {
                    res.setDeliveryDate(TimeUtils.formatDate(orderAmazonDo.getPromisedDeliveryDate()));
                    // res.setDeliveryTime(TimeUtils.formatDate(orderAmazonDo.getPromisedDeliveryDate(), "HH") + "-" + TimeUtils.formatDate(orderAmazonDo.getLastDeliveryDate(), "HH"));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            long storageId =15L;
            //item
            List<OrderOutputProductAddReq> orderOutputProductDetailList = new ArrayList<>();
            List<OrderAmazonVdfItemDo> failedItems = new ArrayList<>();
            if (!CollectionUtils.isEmpty(itemsDoList)) {
                double[] size = new double[4];
                double shipPirce = 99999D;
                //默认仓库先捆包
                for (OrderAmazonVdfItemDo itemsDo : itemsDoList) {
                    Long productId = productInfoService.getProductIdNoThrow(itemsDo.getVendorProductIdentifier(), orderAmazonDo.getCompanyId());
                    if (productId == null) {
                        failOrders.add(StringsUtil.createI18Message(SysConstant.OrderYahoo_Product_Notfound, orderAmazonDo.getPurchaseOrderNumber(), itemsDo.getVendorProductIdentifier()));
                        continue;
                    }
                    if (companyId.intValue() == 84 &&! orderAmazonDo.getSellingParty().isEmpty()) {
                        if (orderAmazonDo.getShipFromParty().contains("FTH")) {
                            storageId = 13L;
                            res.setTips((res.getTips()==null?"":res.getTips()) + orderAmazonDo.getShipFromPartyId());
                        } else if (orderAmazonDo.getShipFromParty().contains("GOE")) {
                            res.setTips((res.getTips()==null?"":res.getTips()) + orderAmazonDo.getShipFromPartyId());
                            storageId = 15L;
                        }
                    }
                    LambdaQueryWrapper<StockRecordDo> wrapper1 = new LambdaQueryWrapper<>();
                    wrapper1.eq(StockRecordDo::getShopId, res.getShopId()).eq(StockRecordDo::getProductInfoId, productId).eq(StockRecordDo::getStorageId, storageId);
                    StockRecordDo stockRecordDo = stockDao.selectOne(wrapper1);
                    int noDeliveredCount = stockDao.getOrderOutCount(productId, res.getShopId(), storageId);
                    if (stockRecordDo == null || stockRecordDo.getCanSellCount() - noDeliveredCount < itemsDo.getOrderedQuantity()) {//优先仓库有库存，优先仓库发货
                        failedItems.add(itemsDo);
                        continue;
                    }
                    OrderOutputProductAddReq productDetail = new OrderOutputProductAddReq();
                    productDetail.setOrderId(orderAmazonDo.getId());
                    productDetail.setProductId(productId);
                    productDetail.setCount(itemsDo.getOrderedQuantity());
                    orderOutputProductDetailList.add(productDetail);
                }
                OrderOutputPackageAddReq packageDetail = new OrderOutputPackageAddReq();
                List<OrderOutputPackageAddReq> packageAddReqList = new ArrayList<>();
                packageDetail.setProductList(orderOutputProductDetailList);
                OrderOutputAddReq addReq = new OrderOutputAddReq();
                BeanUtils.copyProperties(res, addReq);
                packageAddReqList.add(packageDetail);
                addReq.setStorageId(storageId);
                addReq.setPackageList(packageAddReqList);
                //默认仓库库存不足
                if (failedItems.size() < 1 && storageId != 0L) {
                    orderOutputAddReqList.add(addReq);
                } else {
                    List<OrderOutputProductAddReq> productAddList = new ArrayList<>();
                    //剩余一件商品无库存
                    if (failedItems.size() == 1 && failedItems.get(0).getOrderedQuantity() == 1) {
                        storageId = 0L;
                        Long productId = productInfoService.getProductIdNoThrow(failedItems.get(0).getVendorProductIdentifier(), res.getCompanyId());
                        if (productId == null) {
                            failOrders.add(StringsUtil.createI18Message(SysConstant.OrderYahoo_Product_Notfound, orderAmazonDo.getPurchaseOrderNumber(), failedItems.get(0).getVendorProductIdentifier()));
                            continue;
                        }
                        int count = failedItems.get(0).getOrderedQuantity();
                        List<StorageDo> storageDos = storageDao.selectList(null);
                        for (StorageDo storageDo : storageDos) {//遍历仓库是否都有库存
                            LambdaQueryWrapper<StockRecordDo> wrapper2 = new LambdaQueryWrapper();
                            wrapper2.eq(StockRecordDo::getShopId, res.getShopId()).eq(StockRecordDo::getProductInfoId, productId).eq(StockRecordDo::getStorageId, storageDo.getId());
                            StockRecordDo stockRecordDo1 = stockDao.selectOne(wrapper2);

                            size = shipPriceService.countSameSkuSize(new double[4], productId, failedItems.get(0).getOrderedQuantity());
                            int noDeliveredCount1 = stockDao.getOrderOutCount(productId, res.getShopId(), storageDo.getId());
                            if (stockRecordDo1 != null && stockRecordDo1.getCanSellCount() - noDeliveredCount1 >= count) {
                                List<ShipPriceDo> shipPriceDos = shipPriceService.queryByRegionAndSize(res.getPostCode(), size, res.getCod(), res.getShipmentType(), storageDo.getId(), 1, res.getCompanyId());
                                if (shipPriceDos.size() < 1 || shipPriceDos.get(0).getPrice() == 0) {
                                    continue;
                                }
                                if (shipPirce > shipPriceDos.get(0).getPrice()) {//选择最便宜的价格
                                    shipPirce = shipPriceDos.get(0).getPrice();
                                    storageId = storageDo.getId();
                                }
                            }
                        }
                        OrderOutputProductAddReq productDetail = new OrderOutputProductAddReq();
                        productDetail.setProductId(productId);
                        productDetail.setCount(count);
                        productAddList.add(productDetail);
                        OrderOutputPackageAddReq packageDetail1 = new OrderOutputPackageAddReq();
                        if (storageId != 0) {
                            List<OrderOutputPackageAddReq> packageAddReqList1 = new ArrayList<>();
                            packageDetail1.setProductList(productAddList);
                            OrderOutputAddReq addReq1 = new OrderOutputAddReq();
                            BeanUtils.copyProperties(res, addReq1);
                            packageAddReqList1.add(packageDetail1);
                            addReq1.setStorageId(storageId);
                            addReq1.setPackageList(packageAddReqList1);
                            orderOutputAddReqList.add(addReq1);
                        }//TODO 剩一个，都没有库存
                        else {
                            failOrders.add(StringsUtil.createI18Message(SysConstant.OrderYahoo_Stock_NotEnough, orderAmazonDo.getPurchaseOrderNumber(), failedItems.get(0).getVendorProductIdentifier()));
                        }
                    } else {
                        //多件商品无库存，第二优先捆包
                        List<OrderAmazonVdfItemDo> productDoListFailed = new ArrayList<>();
                        LambdaQueryWrapper<StorageDo> lambdaQueryWrapper = new LambdaQueryWrapper();
                        Map<Long, List<OrderAmazonVdfItemDo>> productDoListMapSuccess = new HashMap<>();
                        lambdaQueryWrapper.eq(StorageDo::getSupportShip, 1).ne(StorageDo::getId, storageId);
                        List<StorageDo> storageDos = storageDao.selectList(lambdaQueryWrapper);
                        productAddList = new ArrayList<>();
                        storageId = 0L;
                        if (storageDos != null) {
                            for (StorageDo storageDo : storageDos) {//遍历支持捆包仓库是否都有库存
                                for (OrderAmazonVdfItemDo productDo : failedItems) {
                                    Long productId = productInfoService.getProductIdNoThrow(productDo.getVendorProductIdentifier(), res.getCompanyId());
                                    if (productId == null) {
                                        failOrders.add(StringsUtil.createI18Message(SysConstant.OrderYahoo_Product_Notfound, orderAmazonDo.getPurchaseOrderNumber(), productDo.getVendorProductIdentifier()));
                                        continue;
                                    }
                                    int count = productDo.getOrderedQuantity();
                                    LambdaQueryWrapper<StockRecordDo> wrapper1 = new LambdaQueryWrapper();
                                    wrapper1.eq(StockRecordDo::getShopId, res.getShopId()).eq(StockRecordDo::getProductInfoId, productId).eq(StockRecordDo::getStorageId, storageDo.getId());
                                    StockRecordDo stockRecordDo = stockDao.selectOne(wrapper1);
                                    int noDeliveredCount = stockDao.getOrderOutCount(productId, res.getShopId(), storageDo.getId());

                                    if (stockRecordDo == null || stockRecordDo.getCanSellCount() - noDeliveredCount < count) {
                                        // productDoListFailed.add(productDo);
                                        // continue;
                                    } else {
                                        if (productDoListMapSuccess.get(storageDo.getId()) == null) {
                                            productDoListMapSuccess.put(storageDo.getId(), new ArrayList<>());
                                        }
                                        productDoListMapSuccess.get(storageDo.getId()).add(productDo);
                                    }
                                    // OrderOutputProductAddReq productDetail = new OrderOutputProductAddReq();
                                    // productDetail.setProductId(productId);
                                    // productDetail.setCount(count);
                                    // productAddList.add(productDetail);
                                }
                            }
                            int maxCount = 0;
                            for (Map.Entry<Long, List<OrderAmazonVdfItemDo>> longListEntry : productDoListMapSuccess.entrySet()) {
                                if (maxCount < longListEntry.getValue().size()) {
                                    maxCount = longListEntry.getValue().size();
                                    storageId = longListEntry.getKey();
                                }
                            }
                            if (storageId != 0 && productDoListMapSuccess.size() > 0 && productDoListMapSuccess.get(storageId).size() > 0) {
                                for (OrderAmazonVdfItemDo productDo : failedItems) {
                                    if (productDoListMapSuccess.get(storageId).contains(productDo)) {
                                        Long productId = productInfoService.getProductIdNoThrow(productDo.getVendorProductIdentifier(), res.getCompanyId());
                                        OrderOutputProductAddReq productDetail = new OrderOutputProductAddReq();
                                        productDetail.setProductId(productId);
                                        productDetail.setCount(productDo.getOrderedQuantity());
                                        productAddList.add(productDetail);
                                    } else {
                                        productDoListFailed.add(productDo);
                                    }
                                }
                                OrderOutputPackageAddReq packageDetail1 = new OrderOutputPackageAddReq();
                                List<OrderOutputPackageAddReq> packageAddReqList1 = new ArrayList<>();
                                packageDetail1.setProductList(productAddList);
                                addReq = new OrderOutputAddReq();
                                BeanUtils.copyProperties(res, addReq);
                                packageAddReqList1.add(packageDetail1);
                                addReq.setStorageId(storageId);
                                addReq.setPackageList(packageAddReqList1);
                            } else {
                                productDoListFailed.addAll(failedItems);
                            }
                        } else {
                            productDoListFailed.addAll(failedItems);
                        }
                        if (productDoListFailed.size() != failedItems.size()) {
                            orderOutputAddReqList.add(addReq);
                        }
                        //所有捆包仓库无库存的产品
                        if (productDoListFailed.size() > 0) {//捆包仓库无库存，分别发
                            LambdaQueryWrapper<StorageDo> queryWrapper = new LambdaQueryWrapper();
                            queryWrapper.eq(StorageDo::getSupportShip, 0);
                            List<StorageDo> storageDoList = storageDao.selectList(queryWrapper);
                            for (OrderAmazonVdfItemDo productDo : productDoListFailed) {
                                storageId = 0L;
                                shipPirce = 99999D;
                                Long productId = productInfoService.getProductIdNoThrow(productDo.getVendorProductIdentifier(), res.getCompanyId());
                                int count = productDo.getOrderedQuantity();

                                for (StorageDo storageDo : storageDoList) {//遍历仓库是否都有库存
                                    LambdaQueryWrapper<StockRecordDo> wrapper2 = new LambdaQueryWrapper();
                                    size = shipPriceService.countSameSkuSize(new double[4], productId, 1);
                                    wrapper2.eq(StockRecordDo::getShopId, res.getShopId()).eq(StockRecordDo::getProductInfoId, productId).eq(StockRecordDo::getStorageId, storageDo.getId());
                                    StockRecordDo stockRecordDo1 = stockDao.selectOne(wrapper2);
                                    int noDeliveredCount1 = stockDao.getOrderOutCount(productId, res.getShopId(), storageDo.getId());
                                    if (stockRecordDo1 != null && stockRecordDo1.getCanSellCount() - noDeliveredCount1 >= count) {
                                        List<ShipPriceDo> shipPriceDos = shipPriceService.queryByRegionAndSize(res.getPostCode(), size, res.getCod(), res.getShipmentType(), storageDo.getId(), 1, res.getCompanyId());
                                        if (shipPriceDos.size() < 1 || shipPriceDos.get(0).getPrice() == 0) {
                                            continue;
                                        }
                                        if (shipPirce > shipPriceDos.get(0).getPrice()) {//选择最便宜的价格
                                            shipPirce = shipPriceDos.get(0).getPrice();
                                            storageId = storageDo.getId();
                                        }
                                    }
                                }
                                if (storageId != 0) {
                                    OrderOutputProductAddReq productDetail = new OrderOutputProductAddReq();
                                    productDetail.setProductId(productId);
                                    productDetail.setCount(productDo.getOrderedQuantity());
                                    productAddList.add(productDetail);
                                } else {
                                    //剩余SKU都没有库存
                                    failOrders.add(StringsUtil.createI18Message(SysConstant.OrderYahoo_Stock_NotEnough, orderAmazonDo.getPurchaseOrderNumber(), failedItems.get(0).getVendorProductIdentifier()));
                                }
                            }
                            packageDetail = new OrderOutputPackageAddReq();
                            packageAddReqList = new ArrayList<>();
                            packageDetail.setProductList(productAddList);
                            addReq = new OrderOutputAddReq();
                            BeanUtils.copyProperties(res, addReq);
                            packageAddReqList.add(packageDetail);
                            if (storageId != 0) {
                                addReq.setStorageId(storageId);
                                addReq.setPackageList(packageAddReqList);
                                orderOutputAddReqList.add(addReq);
                            }
                        }
                    }
                }
            } else {
                continue;
            }
            if (orderOutputAddReqList.size() > 0) {
                // operateRecordDao.operateAddRecord(SysConstant.OPERATE_CLICK_SEND, orderAmazonDo.getId(), userId, 10);
            }
        }
        for (OrderOutputAddReq outputAddReq : orderOutputAddReqList) {
            StringBuilder sku = new StringBuilder();
            int cout = 0;
            for (OrderOutputProductAddReq orderOutputProductAddReq : outputAddReq.getPackageList().get(0).getProductList()) {
                cout = cout + orderOutputProductAddReq.getCount();
                if (StringUtils.isNotBlank(sku)) {
                    sku.append(",");
                }
                sku.append(productInfoService.getById(orderOutputProductAddReq.getProductId()).getCommoditySku());
            }
            outputAddReq.setSku(sku.toString());
            outputAddReq.setCount(cout);
        }
        if (b) {
            sendOutMatch(orderOutputAddReqList, userId);
        }

        Map map = new HashMap();
        map.put("orderList", orderOutputAddReqList);
        map.put("failedList", failOrders);
        map.put("storageList", storageDao.selectList(null));
        return SingleResult.success(map);
    }

    @Override
    public SingleResult sendOutNopackage(String orderid, Long userId, Long companyId) {
        List<OrderOutputAddReq> orderOutputAddReqList = new ArrayList<>();
        List<String> failOrders = new ArrayList<>();
        OrderAmazonVdfDo orderAmazonDo = baseMapper.selectById(orderid);
        if (orderAmazonDo == null) {
            throw new BizException(SysConstant.Error_Data_NotExist);
        }
        LambdaQueryWrapper<OrderAmazonVdfItemDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderAmazonVdfItemDo::getPurchaseOrderNumber, orderAmazonDo.getPurchaseOrderNumber());
        List<OrderAmazonVdfItemDo> itemsDoList = orderAmazonVdfItemService.getBaseMapper().selectList(wrapper);
        //订单
        OrderOutputAddReq res = new OrderOutputAddReq();
        res.setPlatform("vdf");
        res.setPlatformNumber(orderAmazonDo.getId() + "");
        res.setSendDate(new Date());
        res.setShopId(orderAmazonDo.getShopId());
        res.setCompanyId(orderAmazonDo.getCompanyId());
        res.setOrderNo(orderAmazonDo.getPurchaseOrderNumber());
        res.setReceiverName(orderAmazonDo.getShipName());
        res.setTelPhone(orderAmazonDo.getShipPhone());
        res.setPostCode(orderAmazonDo.getShipPostalCode());
        res.setArea(orderAmazonDo.getShipStateOrRegion());
        res.setAddress(orderAmazonDo.getShipAddress1());
        if ("YAMATO_LTL".equals(orderAmazonDo.getShipMethod())) {
            res.setTrackId(DicBusinessItemConstant.yamatoExpressYHC);
        } else {
            res.setTrackId(DicBusinessItemConstant.yamatoExpressA);
        }
        if (StringUtils.isNotBlank(orderAmazonDo.getPackingSlipUrl())) {
            res.setTips("需要受领书");
            res.setTrackId(DicBusinessItemConstant.yamatoExpressSLS);
        }
        res.setPackingSlipUrl(orderAmazonDo.getPackingSlipUrl());
        //item
        List<OrderOutputProductAddReq> orderOutputProductDetailList = new ArrayList<>();
        LambdaQueryWrapper<StorageDo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StorageDo::getSupportShip, 0);
        List<StorageDo> storageDoList = storageDao.selectList(queryWrapper);
        for (OrderAmazonVdfItemDo productDo : itemsDoList) {
            long storageId = 0L;
            double shipPirce = 99999D;
            int count = productDo.getOrderedQuantity();

            Long productId = productInfoService.getProductIdNoThrow(productDo.getVendorProductIdentifier(), res.getCompanyId());
            for (StorageDo storageDo : storageDoList) {//遍历仓库是否都有库存
                LambdaQueryWrapper<StockRecordDo> wrapper2 = new LambdaQueryWrapper<>();
                double[] size = shipPriceService.countSameSkuSize(new double[4], productId, 1);
                wrapper2.eq(StockRecordDo::getShopId, res.getShopId()).eq(StockRecordDo::getProductInfoId, productId).eq(StockRecordDo::getStorageId, storageDo.getId());
                StockRecordDo stockRecordDo1 = stockDao.selectOne(wrapper2);
                int noDeliveredCount1 = stockDao.getOrderOutCount(productId, res.getShopId(), storageDo.getId());
                if (stockRecordDo1 != null && stockRecordDo1.getCanSellCount() - noDeliveredCount1 >= count) {
                    List<ShipPriceDo> shipPriceDos = shipPriceService.queryByRegionAndSize(res.getPostCode(), size, res.getCod(), res.getShipmentType(), storageDo.getId(), 1, res.getCompanyId());
                    if (shipPriceDos.size() < 1 || shipPriceDos.get(0).getPrice() == 0) {
                        continue;
                    }
                    if (shipPirce > shipPriceDos.get(0).getPrice()) {//选择最便宜的价格
                        shipPirce = shipPriceDos.get(0).getPrice();
                        storageId = storageDo.getId();
                    }
                }
            }
            if (storageId != 0) {
                OrderOutputProductAddReq productDetail = new OrderOutputProductAddReq();
                productDetail.setProductId(productId);
                productDetail.setCount(productDo.getOrderedQuantity());
                List<OrderOutputProductAddReq> productAddList = new ArrayList<>();
                productAddList.add(productDetail);
                OrderOutputPackageAddReq packageDetail = new OrderOutputPackageAddReq();
                List<OrderOutputPackageAddReq> packageAddReqList = new ArrayList<>();
                packageDetail.setProductList(productAddList);
                OrderOutputAddReq addReq = new OrderOutputAddReq();
                BeanUtils.copyProperties(res, addReq);
                packageAddReqList.add(packageDetail);
                if (storageId != 0) {
                    addReq.setStorageId(storageId);
                    addReq.setPackageList(packageAddReqList);
                    orderOutputAddReqList.add(addReq);
                }
            } else {
                //剩余SKU都没有库存
                failOrders.add(String.format("%s(%s库存不足)", orderAmazonDo.getPurchaseOrderNumber(), productDo.getVendorProductIdentifier()));
            }

        }

        if (orderOutputAddReqList.size() > 0) {
            operateRecordDao.operateAddRecord(SysConstant.OPERATE_CLICK_SEND, orderAmazonDo.getId(), userId, 10);
        }
        for (OrderOutputAddReq outputAddReq : orderOutputAddReqList) {
            StringBuilder sku = new StringBuilder();
            int cout = 0;
            for (OrderOutputProductAddReq orderOutputProductAddReq : outputAddReq.getPackageList().get(0).getProductList()) {
                cout = cout + orderOutputProductAddReq.getCount();
                if (StringUtils.isNotBlank(sku)) {
                    sku.append(",");
                }
                sku.append(productInfoService.getById(orderOutputProductAddReq.getProductId()).getCommoditySku());
            }
            outputAddReq.setSku(sku.toString());
            outputAddReq.setCount(cout);
        }
        Map map = new HashMap();
        map.put("orderList", orderOutputAddReqList);
        map.put("failedList", failOrders);
        map.put("storageList", storageDao.selectList(null));
        return SingleResult.success(map);
    }

    @Override
    public SingleResult sendOutMatch(List<OrderOutputAddReq> orderOutputAddReqList, Long userId) {
        List<String> failOrders = orderOutputService.addAmazonVDFList(orderOutputAddReqList, userId);
        if (failOrders.size() > 0) {
//            return SingleResult.failure("300", String.format("成功导出%d个发货单", orderOutputAddReqList.size() - failOrders.size()), failOrders);
            return SingleResult.failure("300", SysConstant.OrderYahoo_Export_Success, failOrders, orderOutputAddReqList.size() - failOrders.size());

        } else {
            return SingleResult.success(failOrders);
        }
    }

    private LambdaQueryWrapper<OrderAmazonVdfDo> queryBuild(OrderVdfQueryBo bo) {
        LambdaQueryWrapper<OrderAmazonVdfDo> lqw = new LambdaQueryWrapper<>();
        lqw.select(OrderAmazonVdfDo::getId, OrderAmazonVdfDo::getPurchaseOrderNumber, OrderAmazonVdfDo::getCustomerOrderNumber, OrderAmazonVdfDo::getShipMethod, OrderAmazonVdfDo::getTrackingNumber, OrderAmazonVdfDo::getIsSendOut, OrderAmazonVdfDo::getOrderStatus, OrderAmazonVdfDo::getLabelFileUrl, OrderAmazonVdfDo::getOrderDate, OrderAmazonVdfDo::getShipName, OrderAmazonVdfDo::getShipPhone, OrderAmazonVdfDo::getShipPostalCode, OrderAmazonVdfDo::getShipAddress1, OrderAmazonVdfDo::getShipAddress2, OrderAmazonVdfDo::getShipAddress3, OrderAmazonVdfDo::getShopId, OrderAmazonVdfDo::getCompanyId);
        lqw.in(CollUtil.isNotEmpty(bo.getIds()), OrderAmazonVdfDo::getId, bo.getIds());
        lqw.ge(Objects.nonNull(bo.getStartDate()), OrderAmazonVdfDo::getOrderDate, bo.getStartDate());
        lqw.le(Objects.nonNull(bo.getEndDate()), OrderAmazonVdfDo::getOrderDate, bo.getEndDate());
        lqw.eq(StringUtils.isNotBlank(bo.getPurchaseOrderNumber()), OrderAmazonVdfDo::getPurchaseOrderNumber, bo.getPurchaseOrderNumber());
        lqw.eq(Objects.nonNull(bo.getShopId()), OrderAmazonVdfDo::getShopId, bo.getShopId());
        lqw.eq(Objects.nonNull(bo.getCompanyId()), OrderAmazonVdfDo::getCompanyId, bo.getCompanyId());
        lqw.eq(StringUtils.isNotBlank(bo.getOrderStatus()), OrderAmazonVdfDo::getOrderStatus, bo.getOrderStatus());
        lqw.eq(Objects.nonNull(bo.getIsSendOut()), OrderAmazonVdfDo::getIsSendOut, bo.getIsSendOut());
        lqw.like(StringUtils.isNotBlank(bo.getShipMethod()), OrderAmazonVdfDo::getShipMethod, bo.getShipMethod());
        lqw.orderByDesc(OrderAmazonVdfDo::getOrderDate);
        return lqw;
    }


}
